Linux Service unexpectedly died - linux

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.

Related

How to I properly prevent systemd suspend using a script in /lib/systemd/system-sleep/

I'm fairly new to Linux and trying to learn. I'm using Plex Media Server and I'm trying to prevent the system from sleeping while streaming a file. I've searched the internet over the last few days and none of the solutions seem to work. One solution I feel is almost getting me there, but it's not quite working. Here is the script I've placed (and made executable) in /lib/systemd/system-sleep/ (based on this site).
#!/bin/bash
PATH=/sbin:/usr/sbin:/bin:/usr/bin
X_DISPLAY_USERNAME=myusername
plexresume()
{
number_of_sessions=$(curl -s localhost:32400/status/sessions? | sed -n "s/.*MediaContainer size=\"\(.*\)\".*/\1/p")
if [ ${number_of_sessions} -gt 0 ]; then
echo "[$(date +"%Y.%m.%d-%T")] Number of streamers = ${number_of_sessions} Plex session active, cancel suspend" >> /tmp/plex_sleep_log
return 1
else
echo "[$(date +"%Y.%m.%d-%T")] Number of streamers = ${number_of_sessions} Plex session -IN-active, going to sleep now zzzzzzzz........" >> /tmp/plex_sleep_log
return 0
fi
}
plexkeepalive()
{
echo "[$(date +"%Y.%m.%d-%T")] Resuming!!..." >> /tmp/plex_sleep_log
su ${X_DISPLAY_USERNAME} -c "DISPLAY=:0 /usr/bin/xdotool getmouselocation | grep 'x:1 y:1 '" > /dev/null
if [ "$?" == "0" ]; then
su ${X_DISPLAY_USERNAME} -c "DISPLAY=:0 /usr/bin/xdotool mousemove 9 9"
else
su ${X_DISPLAY_USERNAME} -c "DISPLAY=:0 /usr/bin/xdotool mousemove 1 1"
fi
return 0
}
case "$1" in
pre)
plexresume
;;
post)
plexkeepalive
;;
esac
I know it's executing because it's printing to the log file. But even when it's printing that Plex is active, it's still suspending the system. I've manually run the script using sudo outside of systemd and checking the value of $? after, which is 1.
When I use
journalctl -b -u systemd-suspend.service
I see the following:
Sep 26 12:47:03 systemname systemd[1]: Starting System Suspend...
Sep 26 12:47:03 systemname [141890]: /usr/lib/systemd/system-sleep/plexkeepalive failed with exit status 1.
Sep 26 12:47:03 systemname systemd-sleep[141887]: Entering sleep state 'suspend'...
One time I got a successful result, but I'm not sure how it happened:
Sep 26 10:51:45 systemname systemd-sleep[112491]: Entering sleep state 'suspend'...
Sep 26 10:52:25 systemname systemd-sleep[112491]: Failed to put system to sleep. System resumed again: Device or resource busy
Sep 26 10:52:25 systemname su[112556]: (to myusername) root on none
Sep 26 10:52:25 systemname su[112556]: pam_unix(su:session): session opened for user myusername(uid=1000) by (uid=0)
Sep 26 10:52:25 systemname su[112556]: pam_unix(su:session): session closed for user myusername
Sep 26 10:52:25 systemname su[112592]: (to myusername) root on none
Sep 26 10:52:25 systemname su[112592]: pam_unix(su:session): session opened for user myusername(uid=1000) by (uid=0)
Sep 26 10:52:25 systemname su[112592]: pam_unix(su:session): session closed for user myusername
Sep 26 10:52:25 systemname systemd[1]: systemd-suspend.service: Main process exited, code=exited, status=1/FAILURE
Sep 26 10:52:25 systemname systemd[1]: systemd-suspend.service: Failed with result 'exit-code'.
Sep 26 10:52:25 systemname systemd[1]: Failed to start System Suspend.
Sep 26 10:52:25 systemname systemd[1]: systemd-suspend.service: Consumed 2.732s CPU time.
Any help on this issue would be appreciated. I don't understand why returning 1 from the script is not preventing systemd-suspend.service from running. Thank you!

Bash Script to kill linux processes not coming back to terminal

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

Unable to print lines in a loop conditionally

need help on this script where I try to get output related to that command. For example, in the below code
"info related to process and the output should be ps -ef command output and should continue to the next command and print statement likewise"
But i get the lines saying
info related to process and all the commands are being displayed at once.
#!/usr/bin/env python3.7
import os
state = ['process' , 'http status' , 'date info' , 'system']
def comm(com):
for i in state:
for j in com:
print (f"info related to {i}")
os.system(j)
cmd = ['ps -ef | head -2' , 'systemctl status httpd' , 'date' , 'uptime']
comm(cmd)
OUTPUT:
info related to process
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:13 ? 00:00:19 /usr/lib/systemd/systemd -
-switched-root --system --deserialize 22
info related to process
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor
preset: disabled)
Active: active (running) since Wed 2019-03-27 18:27:50 IST; 1 day 2h ago
Docs: man:httpd(8)
man:apachectl(8)
Process: 8585 ExecReload=/usr/sbin/httpd $OPTIONS -k graceful (code=exited,
status=0/SUCCESS)
Main PID: 1367 (httpd)
Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0
B/sec"
Tasks: 6
CGroup: /system.slice/httpd.service
├─1367 /usr/sbin/httpd -DFOREGROUND
├─8597 /usr/sbin/httpd -DFOREGROUND
├─8598 /usr/sbin/httpd -DFOREGROUND
├─8599 /usr/sbin/httpd -DFOREGROUND
├─8600 /usr/sbin/httpd -DFOREGROUND
└─8601 /usr/sbin/httpd -DFOREGROUND
info related to process
Thu Mar 28 21:03:57 IST 2019
info related to process
21:03:57 up 10:50, 4 users, load average: 0.35, 0.09, 0.14
You have two loops, one being nested in the other. That means anything the inner loop does will be executed in every iteration of the outer loop. That's just how loops work, but not what (I presume) you want to do here.
You have commands to be executed by the os module and several state names that are associated with them. From a data-first point of view we could structure them in a dictionary:
commands = {
'process': 'ps -ef',
'http status': 'systemctl status httpd',
'date info': 'date',
'sytem': 'uptime',
}
Now when we iterate over this dictionary, in each iteration we will have both the state name and the command to be run as loop variables. The loops become a single for loop and we end up with:
def comm(commands):
for name, command in commands.items():
print (f"info related to {name}")
os.system(command)

Self duplicate background script

This is a background script test.
When run it launch two processes and I don't understand why.
One stop after sleep 20. And other forgets.
#!/bin/bash
back(){
n=0
while [ 1 ]
do
echo $n
n=$(($n+1))
sleep 5
done
}
back &
sleep 20
exit
command "ps -a" in call:
PID TTY TIME CMD
8964 pts/2 00:00:00 backgroundtest
8965 pts/2 00:00:00 backgroundtest
8966 pts/2 00:00:00 sleep
8982 pts/2 00:00:00 sleep
after sleep 20:
PID TTY TIME CMD
8965 pts/2 00:00:00 backgroundtest
9268 pts/2 00:00:00 sleep
then run forever...
why?
while [ 1 ] is an infinite loop. [ 1 ] is always true.
So back & is an infinite loop, started in background (&), then execution continues with sleep 20, which does end after 20 seconds, leaving you with two processes for 20 seconds (& starts a new process in background), then the infinite one after that.

Bash script not producing desired result

I am running a cron-ed bash script to extract cache hits and bytes served per IP address. The script (ProxyUsage.bash) has two parts:
(uniqueIP.awk) find unique IPs and create a bash script do add up the hits and bytes
run the hits and bytes per IP
ProxyUsage.bash
#!/usr/bin/env bash
sudo gawk -f /home/maxg/scripts/uniqueIP.awk /var/log/squid3/access.log.1 > /home/maxg/scripts/pxyUsage.bash
source /home/maxg/scripts/pxyUsage.bash
uniqueIP.awk
{
arrIPs[$3]++;
}
END {
for (n in arrIPs) {
m++; # count arrIPs elements
#print "Array elements: " m;
arrAddr[i++] = n; # fill arrAddr with IPs
#print i " " n;
}
asort(arrAddr); # sort the array values
for (i = 1; i <= m; i++) { # write one command line per IP address
#printf("#!/usr/bin/env bash\n");
printf("sudo gawk -f /home/maxg/scripts/proxyUsage.awk -v v_Var=%s /var/log/squid3/access.log.1 >> /home/maxg/scripts/pxyUsage.txt\n", arrAddr[i])
}
}
pxyUsage.bash
sudo gawk -f /home/maxg/scripts/proxyUsage.awk -v v_Var=192.168.1.13 /var/log/squid3/access.log.1 >> /home/maxg/scripts/pxyUsage.txt
sudo gawk -f /home/maxg/scripts/proxyUsage.awk -v v_Var=192.168.1.14 /var/log/squid3/access.log.1 >> /home/maxg/scripts/pxyUsage.txt
sudo gawk -f /home/maxg/scripts/proxyUsage.awk -v v_Var=192.168.1.22 /var/log/squid3/access.log.1 >> /home/maxg/scripts/pxyUsage.txt
TheProxyUsage.bash script runs as scheduled and creates the pxyUsage.bash script.
However the pxyUsage.text file is not amended with the latest values when the script runs.
So far I run pxyUsage.bash every day myself, as I cannot figure out, why the result is not written to file.
Both bash scripts are set to execute. Actually the file permissions are below:
-rwxr-xr-x 1 maxg maxg 169 Mar 14 08:40 ProxySummary.bash
-rw-r--r-- 1 maxg maxg 910 Mar 15 17:15 proxyUsage.awk
-rwxrwxrwx 1 maxg maxg 399 Mar 17 06:10 pxyUsage.bash
-rw-rw-rw- 1 maxg maxg 2922 Mar 17 07:32 pxyUsage.txt
-rw-r--r-- 1 maxg maxg 781 Mar 16 07:35 uniqueIP.awk
Any hints appreciated. Thanks.
The sudo(8) command requires a pseudo-tty and you do not have one allocated under cron(8); you do have one allocated when logged in the usual way.
Instead of mucking about with sudo(8), just run the script as the correct user.
If you cannot do that, then in the root crontab, do something like this:
su - username /path/to/mycommand arg1 arg2...
This will work because root can use su(1) without neding a password.

Resources