Bash Script to kill linux processes not coming back to terminal - linux

I am new to Linux environment and working on writing scripts to start and stop few services(nodejs app bundled into executables using 'pkg' module). I want to stop processes by name and found 'killall' command. I tried this command individuaaly and inside bash script. Problem I am facing is, after executing kill command, control does not comeback to terminal and i need to use ctrl+c to get terminal back.
Here is script i tried:
#!/bin/bash
# Run with command : chmod +x /root/myApp/stopserv.sh && /root/myApp/stopserv.sh
echo "Stopping Service1"
nohup killall Service1 &>/dev/null &
echo "Stopping Service2"
nohup killall Service2 &>/dev/null &
echo "Stopping Service3"
nohup killall Service3 &>/dev/null &
echo "Stopping Service4"
nohup killall Service4 &>/dev/null &
And when i run this script, I get response on terminal like below:
root#Phantom-E03E:~/myApp# chmod +x /root/myApp/stopserv.sh && /root/myApp/stopserv.sh
Stopping Service1
Stopping Service2
Stopping Service3
Stopping Service4
root#Phantom-E03E:~/myApp# /root/myApp/startserv.sh: line 17: 29535 Terminated nohup ./Service1 &> /dev/null
/root/myApp/startserv.sh: line 11: 29533 Terminated nohup ./Service2-linux &> /dev/null
/root/myApp/startserv.sh: line 14: 29534 Terminated nohup ./Service3-linux &> /dev/null
/root/myApp/startserv.sh: line 8: 29527 Terminated nohup ./Service4-linux &> /dev/null
I want to check:
Is there any other recommended way to stop executables in linux by name?
How to i get control back to terminal "root#Phantom-E03E:~/myApp#" after running script?
Thanks,
Pooja

Just call the script like:
<path_to_script> && exit

You can do it much better. Actually you can do it in two ways
1. using foreground-background mechanism
2. using systemd - service management ( a lit bit complicated )
using fg / bg
When we run a process using shell (? bash) it will have interactively with our terminal. We can manage this interactivity by
Control-Z (stop it, not quit, just pause)
Control-C (stop it, kill
== quit)
fg ( bringing it back to foreground == interactivity )
bg ( running it in background when it is stopped )
You can use this way manually or using a script. I will show both.
here is a screen-shot of doing manually
using bash
here is a simple script
#!/bin/bash
APP_STATE=$1;
APP_NAME=$2;
# TASKS=( cont stop );
function stop_app(){
APP_PID=$(pidof $APP_NAME);
kill -n 19 $APP_PID;
if [[ $? == '0' ]]; then
echo "$APP_NAME paused!";
else
echo "could not pause $APP_NAME";
fi
}
function continue_app(){
APP_PID=$(pidof $APP_NAME);
kill -n 18 $APP_PID;
if [[ $? == '0' ]]; then
echo "$APP_NAME continued ...";
else
echo "could not continue $APP_NAME";
fi
}
case $APP_STATE in
cont )
continue_app ;;
stop )
stop_app ;;
esac
and screen-shot of running this script
Note bg and fg are interfaces and you can do it in lower level using kill command by sending stop signal and continue signal which my script does it this way.
>>> kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
please notice signals 18 and 19.
For a simple killing a process by name use pkill command.
For a complex management please take look at /etc/systemd/system directory
And if you have a Node.js server up and running and its management use either of pm2 or systemd

Related

ssh port forwarding ("ssh -fNL") doesn't work via expect spawn to automatically provide password

I know that to do port forwarding, the command is ssh -L. I also use other options to decorate it. So for example, a final full command may look like this ssh -fCNL *:10000:127.0.0.1:10001 127.0.0.1. And everything just works after entering password.
Then, because there is not only one port need to be forwarded, I decide to leave the job to shell script and use expect(tcl) to provide passwords(all the same).
Although without a deep understanding of expect, I managed to write the code with the help of Internet. The script succeeds spawning ssh and provides correct password. But I end up finding there is no such process when I try to check using ps -ef | grep ssh and netstat -anp | grep 10000.
I give -v option to ssh and the output seems to be fine.
So where is the problem? I have searched through Internet but most of questions are not about port forwarding. I'm not sure whether it is proper to use expect while I just want to let script automatically provide password.
Here the script.
#!/bin/sh
# Port Forwarding
# set -x
## function definition
connection ()
{
ps -ef | grep -v grep | grep ssh | grep $1 | grep $2 > /dev/null
if [ $? -eq 0 ] ; then
echo "forward $1 -> $2 done"
exit 0
fi
# ssh-keygen -f "$HOME/.ssh/known_hosts" -R "127.0.0.1"
/usr/bin/expect << EOF
set timeout 30
spawn /usr/bin/ssh -v -fCNL *:$1:127.0.0.1:$2 127.0.0.1
expect {
"yes/no" {send "yes\r" ; exp_continue}
"password:" {send "1234567\r" ; exp_continue}
eof
}
catch wait result
exit [lindex \$result 3]
EOF
echo "expect ssh return $?"
echo "forward $1 -> $2 done"
}
## check expect available
which expect > /dev/null
if [ $? -ne 0 ] ; then
echo "command expect not available"
exit 1
fi
login_port="10000"
forward_port="10001"
## check whether the number of elements is equal
login_port_num=$(echo ${login_port} | wc -w)
forward_port_num=$(echo ${forward_port} | wc -w)
if [ ${login_port_num} -ne ${forward_port_num} ] ; then
echo "The numbers of login ports and forward ports are not equal"
exit 1
fi
port_num=${login_port_num}
## provide pair of arguments to ssh main function
index=1
while [ ${index} -le ${port_num} ] ; do
login_p=$(echo ${login_port} | awk '{print $'$index'}')
forward_p=$(echo ${forward_port} | awk '{print $'$index'}')
connection ${login_p} ${forward_p}
index=$((index + 1))
done
Here the output from script
spawn /usr/bin/ssh -v -fCNL *:10000:127.0.0.1:10001 127.0.0.1
OpenSSH_7.2p2 Ubuntu-4ubuntu2.10, OpenSSL 1.0.2g 1 Mar 2016
...
debug1: Next authentication method: password
wang#127.0.0.1's password:
debug1: Enabling compression at level 6.
debug1: Authentication succeeded (password).
Authenticated to 127.0.0.1 ([127.0.0.1]:22).
debug1: Local connections to *:10000 forwarded to remote address 127.0.0.1:10001
debug1: Local forwarding listening on 0.0.0.0 port 10000.
debug1: channel 0: new [port listener]
debug1: Local forwarding listening on :: port 10000.
debug1: channel 1: new [port listener]
debug1: Requesting no-more-sessions#openssh.com
debug1: forking to background
expect ssh return 0
forward 10000 -> 10001 done
This should work for you:
spawn -ignore SIGHUP ssh -f ...
UPDATE:
Another workaround is:
spawn bash -c "ssh -f ...; sleep 1"
UPDATE 2 (a bit explanation):
ssh -f calls daemon() to make itself a daemon. See ssh.c in the souce code:
/* Do fork() after authentication. Used by "ssh -f" */
static void
fork_postauth(void)
{
if (need_controlpersist_detach)
control_persist_detach();
debug("forking to background");
fork_after_authentication_flag = 0;
if (daemon(1, 1) == -1)
fatal("daemon() failed: %.200s", strerror(errno));
}
daemon() is implemented like this:
int
daemon(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close (fd);
}
return (0);
}
There's a race condition (not sure if its the correct term for here) between _exit() in the parent process and setsid() in the child process. Here _exit() would always complete first since "the function _exit() terminates the calling process immediately" and setsid() is much more heavy weight. So when the parent process exits, setsid() is not effective yet and the child process is still in the same session as the parent process. According to the apue book (I'm referring to the 2005 edition, Chapter 10: Signals), SIGHUP "is also generated if the session leader terminates. In this case, the signal is sent to each process in the foreground process group."
In brief:
Expect allocates a pty and runs ssh on the pty. Here, ssh would be running in a new session and be the session leader.
ssh -f calls daemon(). The parent process (session leader) calls _exit(). At this time, the child process is still in the session so it'll get SIGHUP whose default behavior is to terminate the process.
How the workarounds works:
The nohup way (spawn -ignore SIGHUP) is to explicitly ask the process to ignore SIGHUP so it'll not be terminated.
For bash -c 'sshh -f ...; sleep 1', bash would be the session leader and sleep 1 in the end prevents the session leader from exiting too soon. So after sleep 1, the child ssh process's setsid() has already done and child ssh is already in a new process session.
UPDATE 3:
You can compile ssh with the following modification (in ssh.c) and verify:
static int
my_daemon(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
// wait a while for child's setsid() to complete
sleep(1);
// ^^^^^^^^
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close (fd);
}
return (0);
}
/* Do fork() after authentication. Used by "ssh -f" */
static void
fork_postauth(void)
{
if (need_controlpersist_detach)
control_persist_detach();
debug("forking to background");
fork_after_authentication_flag = 0;
if (my_daemon(1, 1) == -1)
// ^^^^^^^^^
fatal("my_daemon() failed: %.200s", strerror(errno));
}

Linux Service unexpectedly died

Running Ubuntu 17.04, I'd like to have a systemctl service which oversees a main bash script, where three programs (here substituted by dummy script foo_script tagged with an argument) run under an endless loop (because of possible program crashes).
The main script, foo_main.sh, works correctly if called from a command line; but the service I'm trying to set up from it crashes soon.
File foo_script.sh:
#!/bin/bash
echo "FooScripting "$1 >> "foo.d/"$1
File loop.sh:
#!/bin/bash
nLoop=0
prgName=$1
prgArg=$2
echo "<< START of "${prgName} ${prgArg}" loop >>"
while :
do
let nLoop=nLoop+1
echo "<< looping "${prgName} ${prgArg}" >>" ${nLoop}
"./"${prgName} ${prgArg}
sleep 1
done
echo "<< END of "${prgName} ${prgArg}" loop >>"
File foo_main.sh:
#!/bin/bash
echo "foo_main start in "${PWD}
./loop.sh "foo_script.sh" "fb" &
sleep 2
./loop.sh "foo_script.sh" "gc" &
./loop.sh "foo_script.sh" "gb" &
echo "foo_main end"
File /etc/systemd/system/food.service:
[Unit]
Description = Foo Daemon
After = network.target
[Service]
Type = simple
# User = <<USER>>
# PIDFile=/var/food.pid
WorkingDirectory = /home/john/bin
ExecStart = /home/john/bin/foo_main.sh
# ExecStop = killall loop.sh
# ExecReload = killall loop.sh && /home/john/bin/foo_main.sh
# Restart = on-abort
[Install]
WantedBy = multi-user.target
What I obtain from every sudo systemctl status food.service (after a start ofc) is almost the same output
● food.service - Foo Daemon
Loaded: loaded (/etc/systemd/system/food.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Sep 28 14:54:30 john-host systemd[1]: Started Foo Daemon.
Sep 28 14:54:30 john-host foo_main.sh[7376]: foo_main script start in /home/john/bin
Sep 28 14:54:30 john-host foo_main.sh[7376]: << START of foo_script.sh fb loop >>
Sep 28 14:54:30 john-host foo_main.sh[7376]: << looping foo_script.sh fb >> 1
Sep 28 14:54:31 john-host foo_main.sh[7376]: << looping foo_script.sh fb >> 2
Sep 28 14:54:32 john-host foo_main.sh[7376]: foo_main script end
Sep 28 15:24:30 john-host foo_main.sh[7921]: << START of foo_script.sh gb loop >>
Sep 28 15:24:30 john-host foo_main.sh[7921]: << START of foo_script.sh gc loop >>
Sep 28 15:24:30 john-host foo_main.sh[7921]: << looping foo_script.sh gb >> 1
Sep 28 15:24:30 john-host foo_main.sh[7921]: << looping foo_script.sh gc >> 1
Another solution is to use Type=oneshot + RemainAfterExit=yes in your /etc/systemd/system/food.service
Look at https://www.freedesktop.org/software/systemd/man/systemd.service.html to refer onshot type of service.
The service file like following should solve your issue too.
[Unit]
Description = Foo Daemon
After = network.target
[Service]
Type = oneshot
RemainAfterExit=yes
# User = <<USER>>
# PIDFile=/var/food.pid
WorkingDirectory = /home/john/bin
ExecStart = /home/john/bin/foo_main.sh
# ExecStop = killall loop.sh
# ExecReload = killall loop.sh && /home/john/bin/foo_main.sh
# Restart = on-abort
[Install]
WantedBy = multi-user.target
Solved... the service was stopped simply because its execution flow ended with foo_main.sh. It was enough to add something like
# ...
./loop.sh "foo_script.sh" "endless_dummy_loop"
Without background ampersand, at the end of foo_main.sh.
Clearly real services are far different from this, but I got the point now.

Segmentation fault while using bash script to generate mobility file

I am using a bash script to generate mobility files (setdest) in ns2 for various seeds. But I am running into this troublesome segmentation fault. Any help would be appreciated. The setdest.cc has been modified, so its not the standard ns2 file.
I will walk you through the problem.
This code in a shell script returns the segmentation fault.
#! /bin/sh
setdest="/root/ns-allinone-2.1b9a/ns-2.1b9a/indep-utils/cmu-scen-gen/setdest/setdest_mesh_seed_mod"
let nn="70" #Number of nodes in the simulation
let time="900" #Simulation time
let x="1000" #Horizontal dimensions
let y="1000" #Vertical dimensions
for speed in 5
do
for pause in 10
do
for seed in 1 5
do
echo -e "\n"
echo Seed = $seed Speed = $speed Pause Time = $pause
chmod 700 $setdest
setdest -n $nn -p $pause -s $speed -t $time -x $x -y $y -l 1 -m 50 > scen-mesh-n$nn-seed$seed-p$pause-s$speed-t$time-x$x-y$y
done
done
done
error is
scengen_mesh: line 21: 14144 Segmentation fault $setdest -n $nn -p $pause -s $speed -t $time -x $x -y $y -l 1 -m 50 >scen-mesh-n$nn-seed$seed-p$pause-s$speed-t$time-x$x-y$y
line 21 is the last line of the shell script (done)
The strange thing is If i run the same setdest command on the terminal, there is no problem! like
$setdest -n 70 -p 10 -s 5 -t 900 -x 1000 -y 1000 -l 1 -m 50
I have made out where the problem is exactly. Its with the argument -l. If i remove the argument in the shell script, there is no problem. Now i will walk you through the modified setdest.cc where this argument is coming from.
This modified setdest file uses a text file initpos to read XY coordinates of static nodes for a wireless mesh topology. the relevant lines of code are
FILE *fp_loc;
int locinit;
fp_loc = fopen("initpos","r");
while ((ch = getopt(argc, argv, "r:m:l:n:p:s:t:x:y:i:o")) != EOF) {
switch (ch) {
case 'l':
locinit = atoi(optarg);
break;
default:
usage(argv);
exit(1);
if(locinit)
fscanf(fp_loc,"%lf %lf",&position.X, &position.Y);
if (position.X == -1 && position.Y == -1){
position.X = uniform() * MAXX;
position.Y = uniform() * MAXY;
}
What i dont get is...
In Shell script..
-option -l if supplied by 0 returns no error,
-but if supplied by any other value (i used 1 mostly) returns this segmentation fault.
In Terminal..
-no segmentation fault with any value. 0 or 1
something to do with the shell script surely. I am amazed what is going wrong where!
Your help will be highly appreciated.
Cheers

Resume a stopped process through command line

I've executed the following C code in Linux CentOS to create a process.
#include <stdio.h>
#include <unistd.h>
int main ()
{
int i = 0;
while ( 1 )
{
printf ( "\nhello %d\n", i ++ );
sleep ( 2 );
}
}
I've compiled it to hello_count. When I do ./hello_count, The output is like this:
hello 0
hello 1
hello 2
...
till I kill it.
I've stopped the execution using the following command
kill -s SIGSTOP 2956
When I do
ps -e
the process 2956 ./hello_count is still listed.
Is there any command or any method to resume (not to restart) the process having process id 2956?
Also, when I stop the process, the command line shows:
[1]+ Stopped ./hello_count
What does the [1]+ in the above line mean?
To continue a stopped process, that is resume use kill -SIGCONT PID
Regd [1]+ that is bash way of handling jobs. For further information try help jobs from bash prompt.

Cron generated by ISPConfig

I have a problem with crontab generated by ISPConfig.
MAILTO=''
* * * * * web9 /usr/bin/wget -q -O /dev/null 'http://inz.isedo.pl/test/cron.php' >/dev/null 2>&1 #inz.isedo.pl
In log, I have a errors:
Feb 16 21:11:01 s /usr/sbin/cron[21697]: (*system*ispc_web9) RELOAD (/etc/cron.d/ispc_web9)
Feb 16 21:11:01 s /USR/SBIN/CRON[23817]: (web9) CMD (/usr/bin/wget -q -O /dev/null 'http://inz.isedo.pl/test/cron.php' >/dev/null 2>&1^I#inz.isedo.pl)
Feb 16 21:11:01 s /USR/SBIN/CRON[23816]: (CRON) error (grandchild #23817 failed with exit status 1)
Does it work from the command line ?
Can you redirect the stdout and stderr to a file (as opposed to null) and pass on the output ?

Resources