Shell script get the right PID - linux

I wrote a little program that I want to start as a service on Opensuse 11.3
This is from the init.d script, it starts my processes as I want but I don't get the right PID.
What am I missing?
echo "Starting DHCPALERT"
for (( i = 1; i <= $DHCP_AL_DAEMONS; i++ ))
do
var="DHCP_AL_$i"
START_CMD="exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &"
eval $START_CMD
echo "PID: "$!
echo "Command: "$START_CMD
done
results in
PID: 47347
Command: (/sbin/startproc -p /var/log/sthserver/dhcpalert/p_2.pid -l /var/log/sthserver/dhcpalert/log_2.log /usr/sbin/dhcpalert -i eth1 -c ./test.sh -a 00:15:5D:0A:16:07 -v )&
but pidof returns some othe pid.
If I try to execute it directly:
exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &
Then I get errors:
startproc: exit status of parent of /usr/sbin/dhcpalert: 1
I suppose because I don't escape the variables the right way?
This is the whole script:
#!/bin/sh
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
DHCPALERT_BIN=/usr/sbin/dhcpalert
#-x FILE exists and is executable
test -x $DHCPALERT_BIN || { echo "$DHCPALERT_BIN not installed";
if [ "$1" = "stop" ]; then exit 0;
else exit 5; fi; }
# Check for existence of needed config file and read it
DHCPALERT_CONFIG=/etc/sysconfig/dhcpalert
#-r FILE exists and is readable
test -r $DHCPALERT_CONFIG || { echo "$DHCPALERT_CONFIG not existing";
if [ "$1" = "stop" ]; then exit 0;
else exit 6; fi; }
# Read config to system VARs for this shell session only same as "source FILE"
. $DHCPALERT_CONFIG
#check for exitstence of the log dir
if [ -d "$DHCP_AL_LOG_DIR" ]; then
echo "exists 1"
echo "exists 2"
echo "exists 3"
if [ "$1" = "start" ]; then
echo "Deleting all old log files from: "
echo "Dir:... "$DHCP_AL_LOG_DIR
rm -R $DHCP_AL_LOG_DIR
mkdir $DHCP_AL_LOG_DIR
fi
else
echo "does not exist 1"
echo "does not exist 2"
echo "does not exist 3"
echo "Directory for Logfiles does not exist."
echo "Dir:... "$DHCP_AL_LOG_DIR
echo "Createing dir..."
mkdir $DHCP_AL_LOG_DIR
fi
. /etc/rc.status
# Reset status of this service
rc_reset
case "$1" in
start)
echo "Starting DHCPALERT"
for (( i = 1; i <= $DHCP_AL_DAEMONS; i++ ))
do
var="DHCP_AL_$i"
exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &
# START_CMD="exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &"
# eval $START_CMD
echo "PID: "$!
# echo "Command: "$START_CMD
done
rc_status -v
;;
stop)
echo -n "Shutting down DHCPALERT "
/sbin/killproc -TERM $DHCPALERT_BIN
rc_status -v
;;
try-restart|condrestart)
if test "$1" = "condrestart"; then
echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
fi
$0 status
if test $? = 0; then
$0 restart
else
rc_reset # Not running is not a failure.
fi
rc_status
;;
restart)
$0 stop
$0 start
rc_status
;;
force-reload)
echo -n "Reload service DHCPALERT "
/sbin/killproc -HUP $DHCPALERT_BIN
rc_status -v
;;
reload)
echo -n "Reload service DHCPALERT "
/sbin/killproc -HUP $DHCPALERT_BIN
rc_status -v
;;
status)
echo -n "Checking for service DHCPALERT "
/sbin/checkproc $DHCPALERT_BIN
rc_status -v
;;
probe)
test /etc/DHCPALERT/DHCPALERT.conf -nt /var/run/DHCPALERT.pid && echo reload
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
exit 1
;;
esac
rc_exit
The configfile:
## Specifiy where to store the Pid files
DHCP_AL_PID_DIR="/var/log/sthserver/dhcpalert/"
##
## Specifiy where to store the Log file
DHCP_AL_LOG_DIR="/var/log/sthserver/dhcpalert/"
##
## is needed to determine how many vars should be read and started!
DHCP_AL_DAEMONS="2"
##
## Then DHCP_AL_<number> to specify the command that one instance of
## dhcpalert should be started
DHCP_AL_1="-i eth0 -c ./test.sh -a 00:15:5D:0A:16:06 -v"
DHCP_AL_2="-i eth1 -c ./test.sh -a 00:15:5D:0A:16:07 -v"

Add exec to it to prevent forking:
START_CMD="(exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}") &"
Update. Please try this script:
#!/bin/bash
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
DHCPALERT_BIN=/usr/sbin/dhcpalert
#-x FILE exists and is executable
[[ -x $DHCPALERT_BIN ]] || {
echo "$DHCPALERT_BIN not installed"
if [ "$1" = "stop" ]; then
exit 0
else
exit 5
fi
}
# Check for existence of needed config file and read it
DHCPALERT_CONFIG=/etc/sysconfig/dhcpalert
#-r FILE exists and is readable
[[ -r $DHCPALERT_CONFIG ]] || {
echo "$DHCPALERT_CONFIG not existing"
if [[ $1 == stop ]]; then
exit 0
else
exit 6
fi
}
# Read config to system VARs for this shell session only same as "source FILE"
. "$DHCPALERT_CONFIG"
#check for exitstence of the log dir
CREATE_DIR=false
if [[ -d $DHCP_AL_LOG_DIR ]]; then
echo "exists 1"
echo "exists 2"
echo "exists 3"
if [[ $1 == start ]]; then
echo "Deleting all old log files from: "
echo "Dir:... $DHCP_AL_LOG_DIR"
rm -R "$DHCP_AL_LOG_DIR"
CREATE_DIR=true
fi
else
echo "does not exist 1"
echo "does not exist 2"
echo "does not exist 3"
echo "Directory for Logfiles does not exist."
CREATE_DIR=true
fi
if [[ $CREATE_DIR == true ]]; then
echo "Dir:... $DHCP_AL_LOG_DIR"
echo "Createing dir..."
mkdir "$DHCP_AL_LOG_DIR" || {
echo "Failed to create directory $DHCP_AL_LOG_DIR"
exit 1
}
fi
. /etc/rc.status
# Reset status of this service
rc_reset
case "$1" in
start)
echo "Starting DHCPALERT"
for (( I = 1; I <= DHCP_AL_DAEMONS; ++I )); do
REF="DHCP_AL_${I}[#]"
COMMAND=(/sbin/startproc -p "${DHCP_AL_PID_DIR}p_${I}.pid" -l "${DHCP_AL_LOG_DIR}log_${I}.log" "$DHCPALERT_BIN" "${!REF}")
echo "COMMAND: ${COMMAND[*]}"
"${COMMAND[#]}" &
PID=$!
echo "PID: $PID"
done
rc_status -v
;;
stop)
echo -n "Shutting down DHCPALERT "
/sbin/killproc -TERM "$DHCPALERT_BIN"
rc_status -v
;;
try-restart|condrestart)
[[ $1 == condrestart ]] && echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
"$0" status ## ??
if [[ $? -eq 0 ]]; then
"$0" restart
else
rc_reset # Not running is not a failure.
fi
rc_status
;;
restart)
"$0" stop
"$0" start
rc_status
;;
force-reload)
echo -n "Reload service DHCPALERT "
/sbin/killproc -HUP "$DHCPALERT_BIN"
rc_status -v
;;
reload)
echo -n "Reload service DHCPALERT "
/sbin/killproc -HUP "$DHCPALERT_BIN"
rc_status -v
;;
status)
echo -n "Checking for service DHCPALERT "
/sbin/checkproc "$DHCPALERT_BIN"
rc_status -v
;;
probe)
[[ /etc/DHCPALERT/DHCPALERT.conf -nt /var/run/DHCPALERT.pid ]] & echo reload
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
exit 1
;;
esac
rc_exit
Config file:
## Specifiy where to store the Pid files
DHCP_AL_PID_DIR="/var/log/sthserver/dhcpalert/"
##
## Specifiy where to store the Log file
DHCP_AL_LOG_DIR="/var/log/sthserver/dhcpalert/"
##
## is needed to determine how many vars should be read and started!
DHCP_AL_DAEMONS="2"
##
## Then DHCP_AL_<number> to specify the command that one instance of
## dhcpalert should be started
DHCP_AL_1=(-i eth0 -c ./test.sh -a 00:15:5D:0A:16:06 -v)
DHCP_AL_2=(-i eth1 -c ./test.sh -a 00:15:5D:0A:16:07 -v)

When you have a shell-command inside parentheses you start a new sub-shell. You run this sub-shell in the background and it's that sub-shells process id you get with $!.
There are two solutions: The first is to not run the /sbin/startproc command in a subshell, but directly and put that in the background. The secomd solution is to monitor the pid file created by /sbin/startproc.

Related

How to replace the string in exec file with multi line in optimized manner

Provided below is executable file. through script i need to endpoints to it in optimized manner.
filename : taoexec
#!/bin/bash
. /etc/init.d/functions
PIDFILE=/var/run/Naming_Service.pid
PORT=
OPTIONS="-p ${PIDFILE}"
RETVAL=0
prog="Naming_Service"
start() {
echo -n $"Starting $prog: "
if [ $UID -ne 0 ]; then
RETVAL=1
failure
else
setsid /usr/local/bin/Naming_Service ${OPTIONS} &
RETVAL=$?
fi
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
if [ $UID -ne 0 ]; then
RETVAL=1
failure
else
killproc /usr/local/bin/Naming_Service
RETVAL=$?
fi
echo
return $RETVAL
}
restart(){
stop
start
}
case "$1" in
start) start ;;
stop) stop ;;
restart) restart ;;
status) status -p ${PIDFILE} ${prog}; RETVAL=$? ;;
*) echo "Usage: $0 {start|stop|status|restart}"; RETVAL=1
esac
from Environment variables I'm reading the port numbers and I try to replace port and hostname into that file. While i'm using below mentioned script ,not achieved. let me know how i can achieve this
NS_HOSTNAME=$(grep "`hostname`" /etc/hosts|awk '{print $1}')
namingService_ports=$NS_PORTS
echo $namingService_ports
IFS=','
read -r -a portArray <<< "$namingService_ports"
for num in "${portArray[#]}";
do
sed 's~^\(OPTIONS\)="\(-p \${PIDFILE\)}~\1'"_$num"'="\2'"_$num"'} -ORBEndpoint iiop://'"$NS_HOSTNAME"':'"$num"'~' <<< 'OPTIONS="-p ${PIDFILE}"' >> "/etc/init.d/tao"
done
I'm expecting the Following output at last, if I provided NS_PORTS=13021,13022,13023
#!/bin/bash
. /etc/init.d/functions
PIDFILE_13021=/var/run/Naming_Service_13021.pid
PIDFILE_13022=/var/run/Naming_Service_13022.pid
PIDFILE_13023=/var/run/Naming_Service_13023.pid
PORT=
OPTIONS_13021="-p ${PIDFILE_13021} -ORBEndpoint iiop://10.12.23.34:13021"
OPTIONS_13022="-p ${PIDFILE_13022} -ORBEndpoint iiop://10.12.23.34:13022"
OPTIONS_13023="-p ${PIDFILE_13023} -ORBEndpoint iiop://10.12.23.34:13023"
start() {
echo -n $"Starting $prog: "
if [ $UID -ne 0 ]; then
RETVAL=1
failure
else
setsid /usr/local/bin/Naming_Service ${OPTIONS_13021} &
setsid /usr/local/bin/Naming_Service ${OPTIONS_13022} &
setsid /usr/local/bin/Naming_Service ${OPTIONS_13023} &
RETVAL=$?
fi
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
if [ $UID -ne 0 ]; then
RETVAL=1
failure
else
killproc /usr/local/bin/Naming_Service
RETVAL=$?
fi
echo
return $RETVAL
}
restart(){
stop
start
}
case "$1" in
start) start ;;
stop) stop ;;
restart) restart ;;
status) status -p ${PIDFILE} ${prog}; RETVAL=$? ;;
*) echo "Usage: $0 {start|stop|status|restart}"; RETVAL=1
esac
Anybody can give the solution for this.
Is there any reason you can't just generate the file from scratch each time the script runs?
#!/bin/bash
FILENAME=/etc/init.d/tao
NS_HOSTNAME=$(grep "`hostname`" /etc/hosts|awk '{print $1}')
namingService_ports=$NS_PORTS
echo $namingService_ports
cat > "$FILENAME" << EOF
#!/bin/bash
. /etc/init.d/functions
PORT=
EOF
IFS=','
read -r -a portArray <<< "$namingService_ports"
for num in "${portArray[#]}" ; do
echo PIDFILE_$num=/var/run/Naming_Service_$num.pid
echo OPTIONS_$num=\"-p \${PIDFILE_$num} -ORBEndpoint iiop://${NS_HOSTNAME}:$num\"
done >> "$FILENAME"

Service status not working

I have the following code for a service that I'm trying to have automatically start on boot.
#!/bin/sh
# Source function library.
. /etc/rc.d/init.d/functions
RETVAL=0
prog='foo'
exec="/usr/sbin/$prog"
pidfile="/var/run/$prog.pid"
lock_file="/var/lock/subsys/$prog"
logfile="/var/log/$prog"
if [ -f /etc/default/foo ]; then
. /etc/default/foo
fi
if [ -z $QUEUE_TYPE ]; then
echo 'ENV variable QUEUE_TYPE has not been set, please set it in /etc/default/foo'
exit 1
fi
get_pid() {
cat "$pidfile"
}
is_running() {
[ -f "$pidfile" ] && ps `get_pid` > /dev/null 2>&1
}
case "$1" in
start)
echo -n "Starting Consul daemon: "
#
daemon --pidfile $pidfile --check foo --user my-user "my app stuff here"
echo
;;
stop)
echo -n 'Stopping Consul daemon: '
killproc foo
echo
;;
status)
status $pidfile
RETVAL=$?
#status -p $pidfile -l $prog
#[ $RETVAL -eq 0 ] && RETVAL=$?
#RETVAL=$?
#if is_running; then
# echo 'Running'
#else
# echo 'Not Running'
#fi
#status foo
#RETVAL=$?
;;
restart)
$0 stop
$0 start
RETVAL=$?
;;
*)
echo 'Usage: foo {start|stop|status|restart}'
exit 1
esac
exit $RETVAL
When I run sudo service foo status it says that it hasn't been started which is correct. After running sudo service foo start and then running the status command, it tells me that the service hasn't been started. I'm not sure what is causing this to happen. I looked at the configurations for other init.d scripts to see how they were handling this and tried to follow their lead. Is there something obvious here that I'm doing wrong or something else that I may be unaware of that's causing this problem?

not to run duplicate instances of service

I am writing a init.d script for kibana
as of not script is running partially, but the issue is if I run run service kibana start even if service is running then second instance start which bothers me I want to add check before starting service, if service is running then dont start second instance. I tried to put if check on "/var/lock/subsys/kibana" but didn't work. Here is my script :
#!/bin/bash
KIBANA_PATH="/opt/kibana4"
DESC="Kibana Daemon"
NAME=kibana
DAEMON=bin/kibana
CONFIG_DIR=$KIBANA_PATH/config/kibana.yml
LOGFILE=/var/log/kibana/kibana.log
#ARGS="agent --config ${CONFIG_DIR} --log ${LOGFILE}"
SCRIPTNAME=/etc/init.d/kibana
PIDFILE=/var/run/kibana.pid
base=kibana
# Exit if the package is not installed
if [ ! -x "$KIBANA_PATH/$DAEMON" ]; then
{
echo "Couldn't find $DAEMON"
exit 99
}
fi
. /etc/init.d/functions
#
# Function that starts the daemon/service
#
do_start()
{
cd $KIBANA_PATH && \
($DAEMON >> $LOGFILE &) && \
success || failure;
}
set_pidfile()
{
pgrep -f "kibana.jar" > $PIDFILE
}
#
# Function that stops the daemon/service
#
do_stop()
{
pid=`cat $PIDFILE`
if checkpid $pid 2>&1; then
# TERM first, then KILL if not dead
kill -TERM $pid >/dev/null 2>&1
usleep 100000
if checkpid $pid && sleep 1 &&
checkpid $pid && sleep $delay &&
checkpid $pid ; then
kill -KILL $pid >/dev/null 2>&1
usleep 100000
fi
fi
checkpid $pid
RC=$?
[ "$RC" -eq 0 ] && failure $"$base shutdown" || success $"$base shutdown"
}
case "$1" in
start)
echo -n "Starting $DESC: "
do_start
touch /var/lock/subsys/$NAME
set_pidfile
;;
stop)
echo -n "Stopping $DESC: "
do_stop
rm /var/lock/subsys/$NAME
rm $PIDFILE
;;
restart|reload)
echo -n "Restarting $DESC: "
do_stop
do_start
touch /var/lock/subsys/$NAME
set_pidfile
;;
status)
echo $DESC
status -p $PIDFILE
echo $!
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 3
;;
esac
echo
exit 0
any help here ?
Thanks
use lockfile -r0 /path/to/lock/file.lck when you start the service. every new access then will retry zero times to create the file. so if that command fails do nothing or start the service otherwise.
lockfile -r0 /path/to/lock/file.lck
if [ "$?" == "0" ]; then
echo "lock does not exist. enter devils land :)"
fi
The following is a pretty standard implementation of this feature used by most init.d scripts.
start () {
[ -d /var/run/nscd ] || mkdir /var/run/nscd
[ -d /var/db/nscd ] || mkdir /var/db/nscd
echo -n $"Starting $prog: "
daemon /usr/sbin/nscd $NSCD_OPTIONS
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/nscd
return $RETVAL
}
...
# See how we were called.
case "$1" in
start)
[ -e /var/lock/subsys/nscd ] || start
RETVAL=$?
;;
...

How to make my init.d script change users

I have this script which I would like to switch to the user "terraria" before starting the daemon. I can't figure out how to do it. My research brings me to bash scripts using su my_user -c, but I don't think that works in this case.
#!/bin/bash
# Terraria daemon
# chkconfig: 345 20 80
# description: Terraria Server
# processname: TerrariaServer.exe
DAEMON_PATH="/usr/Terraria"
DAEMON=TerrariaServer.exe
DAEMONOPTS="-world This_Land.wld -port 7777 "
NAME=TerrariaServer
DESC="Terraria Server"
PIDFILE=/var/run/TerrariaServer.pid
SCRIPTNAME=/etc/init.d/Terraria-Server
case "$1" in
start)
printf "%-50s" "Starting $NAME..."
cd $DAEMON_PATH
PID=`mono $DAEMON $DAEMONOPTS > /dev/null 2>&1 & echo $!`
#echo "Saving PID" $PID " to " $PIDFILE
if [ -z $PID ]; then
printf "%s\n" "Fail"
else
echo $PID > $PIDFILE
printf "%s\n" "Ok"
fi
;;
status)
printf "%-50s" "Checking $NAME..."
if [ -f $PIDFILE ]; then
PID=`cat $PIDFILE`
if [ -z "`ps axf | grep ${PID} | grep -v grep`" ]; then
printf "%s\n" "Process dead but pidfile exists"
else
echo "Running"
fi
else
printf "%s\n" "Service not running"
fi
;;
stop)
printf "%-50s" "Stopping $NAME"
PID=`cat $PIDFILE`
cd $DAEMON_PATH
if [ -f $PIDFILE ]; then
kill -HUP $PID
printf "%s\n" "Ok"
rm -f $PIDFILE
else
printf "%s\n" "pidfile not found"
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {status|start|stop|restart}"
exit 1
esac
Check out the following link for the 'DJB' way of starting up processes as other users:
http://thedjbway.b0llix.net/daemontools/uidgid.html
Also, see:
How to run a command as a specific user in an init script?

How Kill node process on killing forever process

I have a script to start and stop my node.js server.
When I stop the script, the forever process is killed however the node process is not terminated.
Is there any way to stop both forver and node process when I issue
Kill $FOREVER_PID
Here is the script -
#!/bin/bash
path="/Users/aayush/Desktop/node/rest-api"
action="forever errorLog_express.js "
logFile="$path/system.log"
pidFile="$path/pidFile.pid"
#messages
usage="Usage : node-script.sh start|stop"
panic="Panic! nothing to do, exiting"
unknown="Unrecognized parameter"
start="[starting node-forever]"
end="[stopping node-forever]"
notRunning="Process node-forever not running"
alreadyRunning="Process node-forever already running"
if [ -z $1 ]
then
echo $panic
echo $usage
exit 0;
fi
if [ $1 = "start" ]
then
# starting process
dummy="OK"
if [ -f $pidFile ];
then
exit 0
else
cd $path
echo "cd $path"
echo $start
echo $start >> $logFile
$action > /dev/null 2>&1 &
Process_Pid=$!
echo $Process_Pid > $pidFile
echo $dummy
exit 0
fi
elif [ $1 = "stop" ]
then
# stopping process by getting pid from pid file
dummy="OK"
echo $end
echo $end >> $logFile
if [ -f $pidFile ];
then
while IFS=: read -r pid
do
# reading line in variable pid
if [ -z $pid ]
then
dummy="FAILED"
echo "Could not parse pid PANIC ! do 'ps' and check manully"
else
echo "Process Pid : $pid"
kill $pid
fi
done <"$pidFile"
rm $pidFile
echo $dummy
exit 0
else
echo $notRunning
echo "FAILED"
exit 0
fi
else
echo $unknown
echo $usage
exit 0
fi
The final script working for me -
#!/bin/bash
#proccessname: node
USER=node
PWD=node
node=node
forever=forever
path="/Users/aayush/Desktop/node/rest-api"
action="forever start -l forever.log -a -o out.log -e err.log errorLog_express.js "
start(){
cd $path
$action
}
stop(){
/usr/local/bin/forever stopall
}
restart(){
stop
start
}
status(){
/usr/local/bin/forever list
}
#Options
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo $ "usage $0 {start | stop | status | restart}"
exit 1
esac
exit 0
Yes there is, use a signal handler in your script to catch the sigterm and kill the node process.
www.gnu.org/software/bash/manual/html_node/Signals.html
$ killall node
Will kill them.

Resources