Jump to content
Калькуляторы

Вопрос по start-stop-daemon

Есть сервер со старым Debian, в котором используется не systemd, а LSB.

На нем работает IPTV-стриммер на основе VLC, который запускается в изолированном сеансе screen.

Сейчас хочу написать стартер для VLC, который бы автоматически перезапускался в случае падения VLC.

Написанный стартер под спойлером.

Скрытый текст

#!/bin/sh

### BEGIN INIT INFO
# Provides: vlc-daemon
# Required-Start: $syslog
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: IPTV-streamer (VLC)
### END INIT INFO

SELF=$(readlink -f "$0")
NAME=$(basename "$SELF")
BASE=$(dirname "$SELF")
DESC="IPTV-streamer (VLC)"
VLC=$(which cvlc)
CFG="iptv-cam"
MGT="-I telnet --telnet-port 12345 --telnet-password iptv"
UID="vlcd"
GID="vlcd"
LOG=/var/log/vlcd
PID=/var/run/$NAME.pid

[ -x "$VLC" ] || exit 1
. /lib/init/vars.sh
. /lib/lsb/init-functions

VERBOSE=yes

SSD_START="--start --quiet --chuid=$UID"
SSD_STOP="--stop --quiet"
SSD_FIND="--pidfile $PID --name $NAME"

VLC_ARGS="--quiet --daemon --pidfile $PID $MGT"
VLC_ARGS="$VLC_ARGS --file-logging --logmode text --logfile $LOG/$CFG.log --log-verbose 1"
VLC_ARGS="$VLC_ARGS --ttl=5 --vlm-conf=$BASE/$CFG.conf"

echo >> $LOG/$NAME.log
date +"*** DATE %F, TIME %T, TZ %Z%:z" >> $LOG/$NAME.log
echo "$DESC" >> $LOG/$NAME.log
echo "DIR: $BASE" >> $LOG/$NAME.log
echo "CMD: $0 $*" >> $LOG/$NAME.log
echo "VLC: $VLC" >> $LOG/$NAME.log
echo "ARG: $VLC_ARGS" >> $LOG/$NAME.log

do_start()
{
        if [ ! -e "$LOG/$CFG.log" ]; then
                touch "$LOG/$CFG.log"
                chown $UID:$GID "$LOG/$CFG.log"
                chmod 640 "$LOG/$CFG.log"
        fi
        if [ ! -e "$PID" ]; then
                touch "$PID"
                chown $UID:$GID "$PID"
                chmod 644 "$PID"
        fi
        start-stop-daemon $SSD_START $SSD_FIND --exec $VLC --test > /dev/null \
                || return 1
        start-stop-daemon $SSD_START $SSD_FIND --exec $VLC -- $VLC_ARGS >> $LOG/$NAME.log 2>&1 \
                || return 2
}

do_stop()
{
        start-stop-daemon $SSD_STOP --retry=TERM/30/KILL/5 $SSD_FIND
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        start-stop-daemon $SSD_STOP --oknodo --retry=0/30/KILL/5 --exec $VLC
        [ "$?" = 2 ] && return 2
        rm -f $PID
        return "$RETVAL"
}

do_reload() {
        start-stop-daemon $SSD_STOP --signal 1 $SSD_FIND
        return 0
}

case "$1" in
        start)
                [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
                do_start
                case "$?" in
                        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
                esac
                ;;
        stop)
                [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
                do_stop
                case "$?" in
                        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
                esac
                ;;
        restart)
                log_daemon_msg "Restarting $DESC" "$NAME"
                do_stop
                case "$?" in
                  0|1)
                        sleep 5
                        do_start
                        case "$?" in
                                0) log_end_msg 0 ;;
                                1) log_end_msg 1 ;; # Old process is still running
                                *) log_end_msg 1 ;; # Failed to start
                        esac
                        ;;
                  *)
                        log_end_msg 1
                        ;;
                esac
                ;;
        reload)
                echo "reload"
                #del media
                #load $CFG.conf
                ;;
        status)
                status_of_proc -p $PID "$VLC" "$NAME" && exit 0 || exit $?
                ;;
        stats)
                echo "stats"
                ;;
        *)
                echo "Usage: ${NAME} {start|stop|restart|reload|status|stats}"
                exit 1
                ;;
esac

:

 

VLC в режиме сервиса стартует, IPTV транслирует.

Но почему-то не останавливается.

Процедура остановки такая:

do_stop()
{
        start-stop-daemon $SSD_STOP --retry=TERM/30/KILL/5 $SSD_FIND
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        start-stop-daemon $SSD_STOP --oknodo --retry=0/30/KILL/5 --exec $VLC
        [ "$?" = 2 ] && return 2
        rm -f $PID
        return "$RETVAL"
}

При выполнении остановки pid-файл удаляется (то есть start-stop-daemon возвращает 0), но процесс продолжает работать.

Я что-то не доделал? Или причина в том, что имя демона и имя исполняемого файла у меня не совпадает?

Share this post


Link to post
Share on other sites

 Каким sigusr процесс прибиваете ? -9 ?

Share this post


Link to post
Share on other sites

Никаким.

Если прибивать вручную, то работают и 15, и 9.

Share this post


Link to post
Share on other sites
1 час назад, alibek сказал:

Никаким.

Если прибивать вручную, то работают и 15, и 9.

 В древних версиях неоднократно встречал, что пид-файлы не соответствуют демону, или не туда пишутся. Поэтому грепал ps, авкашил пид и килял. Слава догу, во freebsd появился killall  с именем процесса. Для начала у демона уточните, куда он пид пишет, и соответствует ли сей пид из файла реальному пиду из ps.

Share this post


Link to post
Share on other sites

Все соответствует.

Если перед удалением pid-файла выполнить kill $(cat $PID) , то процесс завершается.

Вопрос в том, почему start-stop-daemon этого не делает.

Share this post


Link to post
Share on other sites

Может через monit проще запилить?

Share this post


Link to post
Share on other sites

 Возможно вопрос детский, из серии руками работает а из крона нет ? path не установлен правильно, и утили просто не находятся.

Share this post


Link to post
Share on other sites

Дело не в path, тогда бы утилита просто не выполнялась.

Она же выполняется, но процесс продолжает работать.

 

Сейчас я процедуру остановки дополнил "костылями":

do_stop()
{
        start-stop-daemon $SSD_STOP --retry=TERM/30/KILL/5 $SSD_FIND
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        start-stop-daemon $SSD_STOP --oknodo --retry=0/30/KILL/5 --exec $VLC
        [ "$?" = 2 ] && return 2
        kill $(cat $PID) > /dev/null 2>&1
        sleep 5
        kill -KILL $(cat $PID) > /dev/null 2>&1
        rm -f $PID
        return "$RETVAL"
}

В таком виде процесс убивается.

Но не понятно, почему start-stop-daemon этого не выполняет, у него ведь тоже TERM и KILL указаны.

 

7 часов назад, murano сказал:

Может через monit проще запилить?

Мониторинг много чем можно организовать, но вначале нужно скрипт-стартер довести до рабочего состояния, чтобы он корректно запускал/останавливал сервис.

Share this post


Link to post
Share on other sites

И всё же, из консоли оно работает, с --pidfile и --name? start-stop-daemon проверяет соответствие pid и process name.

Share this post


Link to post
Share on other sites

Да, хорошая мысль, я что-то не сообразил проверить.

# start-stop-daemon --stop --verbose --pidfile /var/run/vlc-daemon.pid --name vlc-daemon --retry=TERM/30/KILL/5
No vlc-daemon found running; none killed.

# start-stop-daemon --status --verbose --pidfile /var/run/vlc-daemon.pid --name vlc-daemon && echo ok || echo fail $?
fail 1

# start-stop-daemon --status --verbose --pidfile /var/run/vlc-daemon.pid  && echo ok || echo fail $?
ok

То есть, хоть я и задавал при запуске --name vlc-daemon, он его все равно не находит.

Если убрать --name и оставить только --pidfile, то все работает.

 

Текущий стартер под спойлером.

Скрытый текст

#!/bin/sh

### BEGIN INIT INFO
# Provides: vlc-daemon
# Required-Start: $syslog
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: IPTV-streamer (VLC)
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin
SELF=$(readlink -f "$0")
NAME=$(basename "$SELF")
BASE=$(dirname "$SELF")
DESC="IPTV-streamer (VLC)"
VLC=$(which cvlc)
CFG="ipcam-cam"
MGT="-I telnet --telnet-port 12345 --telnet-password iptv"
UID="vlcd"
GID="vlcd"
LOG=/var/log/vlcd
PID=/var/run/$NAME.pid

[ -x "$VLC" ] || exit 1
. /lib/init/vars.sh
. /lib/lsb/init-functions

VERBOSE=yes

SSD_START="--start --quiet --chuid=$UID --name $NAME"
SSD_STOP="--stop --quiet"
SSD_FIND="--pidfile $PID"

VLC_ARGS="--quiet --daemon --pidfile $PID $MGT"
VLC_ARGS="$VLC_ARGS --file-logging --logmode text --logfile $LOG/$CFG.log --log-verbose 0"
VLC_ARGS="$VLC_ARGS --ttl=5 --vlm-conf=$BASE/$CFG.conf"

echo >> $LOG/$NAME.log
date +"*** DATE %F, TIME %T, TZ %Z%:z" >> $LOG/$NAME.log
echo "$DESC" >> $LOG/$NAME.log
echo "DIR: $BASE" >> $LOG/$NAME.log
echo "CMD: $0 $*" >> $LOG/$NAME.log
echo "VLC: $VLC" >> $LOG/$NAME.log
echo "ARG: $VLC_ARGS" >> $LOG/$NAME.log

do_start()
{
        if [ ! -e "$LOG/$CFG.log" ]; then
                touch "$LOG/$CFG.log"
                chown $UID:$GID "$LOG/$CFG.log"
                chmod 640 "$LOG/$CFG.log"
        fi
        if [ ! -e "$PID" ]; then
                touch "$PID"
                chown $UID:$GID "$PID"
                chmod 644 "$PID"
        fi
        start-stop-daemon $SSD_START $SSD_FIND --exec $VLC --test > /dev/null \
                || return 1
        start-stop-daemon $SSD_START $SSD_FIND --exec $VLC -- $VLC_ARGS >> $LOG/$NAME.log 2>&1 \
                || return 2
}

do_stop()
{
        start-stop-daemon $SSD_STOP --retry=TERM/30/KILL/5 $SSD_FIND
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        start-stop-daemon $SSD_STOP --oknodo --retry=0/30/KILL/5 --exec $VLC
        [ "$?" = 2 ] && return 2
        rm -f $PID
        return "$RETVAL"
}

do_reload() {
        start-stop-daemon $SSD_STOP --signal 1 $SSD_FIND
        return 0
}

case "$1" in
        start)
                [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
                do_start
                case "$?" in
                        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
                esac
                ;;
        stop)
                [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
                do_stop
                case "$?" in
                        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
                esac
                ;;
        restart)
                log_daemon_msg "Restarting $DESC" "$NAME"
                do_stop
                case "$?" in
                  0|1)
                        sleep 5
                        do_start
                        case "$?" in
                                0) log_end_msg 0 ;;
                                1) log_end_msg 1 ;; # Old process is still running
                                *) log_end_msg 1 ;; # Failed to start
                        esac
                        ;;
                  *)
                        log_end_msg 1
                        ;;
                esac
                ;;
        reload)
                echo "reload"
                #del media
                #load $BASE/$CFG.conf
                ;;
        status)
                status_of_proc -p $PID "$VLC" "$NAME" && exit 0 || exit $?
                ;;
        stats)
                echo "stats"
                ;;
        *)
                echo "Usage: ${NAME} {start|stop|restart|reload|status|stats}"
                exit 1
                ;;
esac

:

 

 

Share this post


Link to post
Share on other sites

Безопаснее не убирать проверку совсем, а исправить значение --name.

Share this post


Link to post
Share on other sites

Если бы еще знать, какое name он ищет.

Я полагал, что ищется тот name, который был указан при запуске сервиса (и это имя отличается от имени исполняемого файла).

Более того, если там должно быть имя процесса, то я его в общем случае могу не знать — например я запускаю cvlc, однако в списке процессов вижу vlc.

Share this post


Link to post
Share on other sites
3 часа назад, alibek сказал:

Более того, если там должно быть имя процесса, то я его в общем случае могу не знать — например я запускаю cvlc, однако в списке процессов вижу vlc.

 Ps -axw | grep -i vlc. Иногда по ps процессы показываются как задача с путем запуска

 вот во free10

22346  -  S         0:04.30 /usr/local/sbin/httpd

или

 3443  0- S       102:49.69 ./ts3server

 

  Тимспик иногда умирает и падает, мониторю падение примерно так

 

RESULT1=`/bin/ps -ax |/usr/bin/grep ts3server |/usr/bin/grep -v grep |/usr/bin/wc -l`
if [ "$RESULT1" = "       1" ]
/bin/echo "TS Ok $RESULT1"

else
/bin/echo "TS Down Restarted =$RESULT1= loss"

// тут рестарт

fi

 

 С пидом заморачиваться тут не стал, есть в списке процессов строчка - живой, нету - сдох.

 

Share this post


Link to post
Share on other sites

Я бы написал что-то типа:

 

RESULT1=`/bin/ps -axc | /usr/bin/grep -c ts3server"

 

:)

Share this post


Link to post
Share on other sites
1 час назад, vop сказал:

Я бы написал что-то типа:

 

RESULT1=`/bin/ps -axc | /usr/bin/grep -c ts3server"

 

:)

Ага. И получить почти всегда истину. Грепа-то самого кто убирать будет? :-)

Share this post


Link to post
Share on other sites

 Да ладно вам костыли обсуждать :) Накостылено давно, минут за 10, работает да и буй с ним. Почему пидфайл не стал использовать - он просто остается при умершем процессе. Ну и синтаксис ключей утилей - он бывает довольно разный, использовал более-менее стандартные.

 

 Ну и вдогонку, если пидфайл есть, то ps $(cat $PID) выдаст имя процесса, если он есть конечно.

Share this post


Link to post
Share on other sites
On 5/18/2019 at 9:09 PM, snvoronkov said:

Ага. И получить почти всегда истину. Грепа-то самого кто убирать будет? :-)

Вот там в команде ps есть пуковка це. Внимание вопрос - а нахрена она там нужна? :)

 

Share this post


Link to post
Share on other sites
2 часа назад, vop сказал:

Вот там в команде ps есть пуковка це. Внимание вопрос - а нахрена она там нужна? :)

А действительно? Прикольно.

Век живи, блин, век учись. :-) Причем нашел и в BSD, и в POSIX.

Share this post


Link to post
Share on other sites

По итогам недели могу сказать, что скрипт по запуску/перезапуску VLC отрабатывает отлично.

Под спойлером выкладываю скрипты, может кому пригодится.

 

Скрипт-стартер (для LSB или systemd):

Скрытый текст

#!/bin/sh

### BEGIN INIT INFO
# Provides: vlc-daemon
# Required-Start: $syslog
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: IPTV-streamer (VLC)
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin
SELF=$(readlink -f "$0")
NAME=$(basename "$SELF")
BASE=$(dirname "$SELF")
DESC="IPTV-streamer (VLC)"
VLC=$(which cvlc)
CFG="iptv-cam"
MGT="-I telnet --telnet-port 12345 --telnet-password iptv"
UID="vlcd"
GID="vlcd"
LOG=/var/log/vlcd
PID=/var/run/$NAME.pid

[ -x "$VLC" ] || exit 1
. /lib/init/vars.sh
. /lib/lsb/init-functions

VERBOSE=yes

SSD_START="--start --quiet --chuid=$UID --name $NAME"
SSD_STOP="--stop --quiet"
SSD_FIND="--pidfile $PID"

VLC_ARGS="--quiet --daemon --pidfile $PID $MGT"
VLC_ARGS="$VLC_ARGS --file-logging --logmode text --logfile $LOG/$CFG.log --log-verbose 0"
VLC_ARGS="$VLC_ARGS --ttl=5 --vlm-conf=$BASE/$CFG.conf"

echo >> $LOG/$NAME.log
date +"*** DATE %F, TIME %T, TZ %Z%:z" >> $LOG/$NAME.log
echo "$DESC" >> $LOG/$NAME.log
echo "DIR: $BASE" >> $LOG/$NAME.log
echo "CMD: $0 $*" >> $LOG/$NAME.log
echo "VLC: $VLC" >> $LOG/$NAME.log
echo "ARG: $VLC_ARGS" >> $LOG/$NAME.log

do_start()
{
        if [ ! -e "$LOG/$CFG.log" ]; then
                touch "$LOG/$CFG.log"
                chown $UID:$GID "$LOG/$CFG.log"
                chmod 640 "$LOG/$CFG.log"
        fi
        if [ ! -e "$PID" ]; then
                touch "$PID"
                chown $UID:$GID "$PID"
                chmod 644 "$PID"
        fi
        start-stop-daemon $SSD_START $SSD_FIND --exec $VLC --test > /dev/null \
                || return 1
        start-stop-daemon $SSD_START $SSD_FIND --exec $VLC -- $VLC_ARGS >> $LOG/$NAME.log 2>&1 \
                || return 2
}

do_stop()
{
        start-stop-daemon $SSD_STOP --retry=TERM/30/KILL/5 $SSD_FIND
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        start-stop-daemon $SSD_STOP --oknodo --retry=0/30/KILL/5 --exec $VLC
        [ "$?" = 2 ] && return 2
        #kill -KILL $(cat $PID) > /dev/null 2>&1 && sleep 2
        rm -f $PID
        return "$RETVAL"
}

do_reload() {
        start-stop-daemon $SSD_STOP --signal 1 $SSD_FIND
        return 0
}

case "$1" in
        start)
                [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
                do_start
                case "$?" in
                        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
                esac
                ;;
        stop)
                [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
                do_stop
                case "$?" in
                        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
                esac
                ;;
        restart)
                log_daemon_msg "Restarting $DESC" "$NAME"
                do_stop
                case "$?" in
                  0|1)
                        sleep 5
                        do_start
                        case "$?" in
                                0) log_end_msg 0 ;;
                                1) log_end_msg 1 ;; # Old process is still running
                                *) log_end_msg 1 ;; # Failed to start
                        esac
                        ;;
                  *)
                        log_end_msg 1
                        ;;
                esac
                ;;
        reload)
                echo "reload"
                #del media
                #load $BASE/$CFG.conf
                ;;
        status)
                status_of_proc -p $PID "$VLC" "$NAME" && exit 0 || exit $?
                ;;
        stats)
                echo "stats"
                ;;
        *)
                echo "Usage: ${NAME} {start|stop|restart|reload|status|stats}"
                exit 1
                ;;
esac

:

 

 

Скрипт-перезапускалка (добавляется в cron):

Скрытый текст

#!/bin/sh

PIDFILE=/var/run/vlc-daemon.pid
LOGFILE=/var/log/vlcd/iptv-cam.log

[ ! -e "$PIDFILE" ] && exit 0

LEN=$(stat --printf="%s" $LOGFILE)
PID=$(cat $PIDFILE)
CPU=$(ps p $PID -o pcpu=)
MEM=$(ps p $PID -o pmem=)

if [ -z "$MEM" ]; then
        echo
        echo "*** `date +'%F %T'`: process not found (pid $PID), restarting"
        echo
        /etc/init.d/vlc-daemon restart
        exit 1
fi

MEM=`echo $MEM | awk '{print int(10*$1)}'`
if [ "$MEM" -gt 150 ]; then
        echo
        echo "*** `date +'%F %T'`: high memory usage $(($MEM/10))%, restarting"
        echo
        /etc/init.d/vlc-daemon restart
        exit 1
fi

LEN=`echo $LEN | awk '{print int($1/1024/1024)}'`
if [ "$LEN" -gt 20 ]; then
        echo
        echo "*** `date +'%F %T'`: truncate log-file (size $LEN MB)"
        echo
        #truncate --size 0 $LOGFILE
        tail -n 200 $LOGFILE | tee $LOGFILE > /dev/null
        exit 0
fi

 

Скрипт проверяет краш VLC (отсутствие процесса) или утечки памяти и перезапускает основной скрипт.

 

Из мистического — почему-то все краши и глюки VLC случаются ночью, обычно в период с 2 до 3 часов.

В светлое время суток работает как часы.

Share this post


Link to post
Share on other sites
13 минут назад, alibek сказал:

Скрипт проверяет краш VLC (отсутствие процесса) или утечки памяти и перезапускает основной скрипт.

Что только люди не сделают чтобы monit не ставить. :-)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this