CentOS 6, service с несколькими процессами

carusya

Суть такова: есть такой stunnel, софт, позволяющий заворачивать в SSL общение по некоторым протоколам. Может помочь в такой ситуации: если вы используете почтовый клиент, не умеющий SMTPS/IMAPS, а ваш почтовый сервер отказывается работать по протоколам без SSL.
Так вот, на каждый потенциальный туннель он поднимает отдельный процесс. То есть, у меня настроено 6 туннелей - он поднимает шесть процессов.
Далее, решил я запускать его как service, стащил из интернета init скрипт (простой, как линейка), который почти работает. Некорректно отрабатывает вот это:
 stop() {
if [ ! -f $LOCK_FILE ]; then
echo "stunnel is not running!"
exit 0

else

echo -n $"Shutting down $prog: "
killproc stunnel
RETVAL=$?
[ $RETVAL -eq 0 ]
rm -f $LOCK_FILE
echo
return $RETVAL

fi
}

Он убивает только пять процессов из шести, и результат работы service stunnel stop вот такой:
 [co-sslmailproxy ~]# ps -e | grep stunnel
1386 ? 00:00:00 stunnel
1387 ? 00:00:00 stunnel
1388 ? 00:00:00 stunnel
1389 ? 00:00:00 stunnel
1390 ? 00:00:00 stunnel
1391 ? 00:00:00 stunnel
[co-sslmailproxy ~]# service stunnel stop
Shutting down stunnel: [ OK ]
[co-sslmailproxy ~]# ps -e | grep stunnel
1391 ? 00:00:00 stunnel
[co-sslmailproxy ~]# service stunnel start
Starting stunnel:
[co-sslmailproxy ~]# ps -e | grep stunnel
1391 ? 00:00:00 stunnel
[co-sslmailproxy ~]# killall stunnel
[co-sslmailproxy ~]# ps -e | grep stunnel
[co-sslmailproxy ~]# service stunnel start
Starting stunnel: [ OK ]
[co-sslmailproxy ~]# ps -e | grep stunnel
1913 pts/0 00:00:00 stunnel
1914 pts/0 00:00:00 stunnel
1915 pts/0 00:00:00 stunnel
1916 pts/0 00:00:00 stunnel
1917 pts/0 00:00:00 stunnel
1918 ? 00:00:00 stunnel
[co-sslmailproxy ~]#

То есть, пока руками не доубъеш оставшийся процесс, сервис обратно не запускается.
Как думаете, можно ли это пофиксить?
Так то мне некритично, но хотелось бы исправить такой глупый косяк.

Marinavo_0507

systemd говорят нужен
ну или выяснить, почему процесс не убивается

carusya

У меня на systemd аллергия, я ретроград и вообще виндузятник =(
Как вообще отлаживать init скрипты, этот killproc же простым смертным недоступен?

YUAL

Почему недоступен. Это функция, которая подгружается в начале инит скрипта командой . /etc/init.d/functions
набери в терминале
 .  /etc/init.d/functions 

carusya

Ладно, я думаю, он не виноват. Начал искать, чем отличаются процессы. Нарыл
 

[co-sslmailproxy ~]# ps xao pid,ppid,pgid,sid,comm

PID PPID PGID SID COMMAND
2118 1 2109 1996 stunnel
2119 1 2109 1996 stunnel
2120 1 2109 1996 stunnel
2121 1 2109 1996 stunnel
2122 1 2109 1996 stunnel
2123 1 2123 2123 stunnel

У всех родитель инит (удивительное рядом =) ), но последний, который отказывается убиваться, отличается иным PGID и SID. Это так и нужно?
Нашел в конфиге строчки
 setuid = nobody
setgid = nobody

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

Marinavo_0507

попробуй команду killall
может эта штука просто не обрабатывает сигнал?

carusya

попробуй команду killall
может эта штука просто не обрабатывает сигнал?
Я хз, когда ее убиваешь через killall, она в логе пишет
 
 
2015.01.29 14:02:09 LOG5[2038:140694512555968]: Received signal 15; terminating
2015.01.29 14:02:09 LOG7[2038:140694512555968]: removing pid file /stunnel.pid

вроде бы 15 - это SIGTERM, и killproc вроде тоже посылает его.
заменить его на killall я тоже уже пробовал, получаю вообще китайскую грамоту:
 
 [co-sslmailproxy ~]# vi /etc/init.d/stunnel
[co-sslmailproxy ~]# service stunnel stop
Shutting down stunnel: /sbin/service: line 66: 1568 Terminated env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" ${OPTIONS}
[co-sslmailproxy ~]#

И хоть процессы и убились, но инит скрипт на этом вылетел, не удалив лок файл

smit1

И хоть процессы и убились, но инит скрипт на этом вылетел, не удалив лок файл
Он сам себя, случаем, не убивает?

carusya

Я же говорю, что не понимаю, что это значит.
Shutting down stunnel: /sbin/service: line 66: 1568 Terminated env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" ${OPTIONS}

Marinavo_0507

killall `which stunnel`

carusya

Да, по полному пути к бинарику работает. Видимо, правда в первом варианте с killall скрипт убивал сам себя.
Не конечно зелененького [OK] об остановленном процессе, но это уже ^_^
Спасибо!

Marinavo_0507

ну теперь можно разобраться в коде функции killproc чтоб посмотреть, что она делает не так

Ivan8209

> killall `which stunnel`
Убивать все похожие процессы, конечно, самый лучший подход,
чисто линуксовый.
---
A25: линуха рулит, а вы все остальные - в гробу сасёте, разлагаитись,
ваняити и абастряитись.. вот!

Ivan8209

> Я же говорю, что не понимаю, что это значит.
Это означает, что процесс получил сигнал и завершился с соответствующим статусом.
Оно же намекает на то, что твой killall убил скрипт.
А разгадка проста: нефига убивать процессы методом killall,
надо развести демоны по разным pid-файлам и убивать именно те,
которые были запущены скриптами, а не все подряд.
---
Q9: А почему Линукс не ОС?
A9: ОС - это БЗДя

carusya

Это означает, что процесс получил сигнал и завершился с соответствующим статусом.
Оно же намекает на то, что твой killall убил скрипт.
Я хз, как оно на самом деле работает (в смысле, рожает много процессов). С одной стороны, родитель у всех инит. С другой - именно тот процесс, pid которого в pid файле, не завершается killproc (по service stop), но если до service stop, когда живы все шесть процессов, убить его по pid остальные тоже завершаются. Может тогда поправить скрипт так, чтобы он только его завершал, а остальные сами помрут?

Ivan8209

> Я хз, как оно на самом деле работает (в смысле, рожает много процессов).
> С одной стороны, родитель у всех инит.
Если ты хочешь продолжать работать со связанными задачами,
тебе очень надо в этом разобраться. Иначе никак.
> С другой - именно тот процесс, pid которого в pid файле,
> не завершается killproc (по service stop),
Стоит посмотреть, что именно они туда записали.
Это линух, там может быть что угодно.
Пока что у меня складывается впечатление, что твой killproc
работает через pkill или killall, а не через pid-файл.
Возможно, что это из-за того, что он ожидает файл в /var/run,
а на самом деле он в /, как это написано в журнале.
Или ещё что-то подобное.
> но если до service stop, когда живы все шесть процессов, убить его по pid
> остальные тоже завершаются.
Если это правда, то это весьма интересное решение, я бы сказал.
> Может тогда поправить скрипт так, чтобы он только его завершал,
> а остальные сами помрут?
Ну, если это работает...
---
Q9: А почему Линукс не ОС?
A9: ОС - это БЗДя

carusya

Пока что у меня складывается впечатление, что твой killproc
работает через pkill или killall, а не через pid-файл.
Возможно, что это из-за того, что он ожидает файл в /var/run,
а на самом деле он в /, как это написано в журнале.
Или ещё что-то подобное.
В логах пишет, что как будто в / потому, что в конфиге chroot = /var/run/stunnel. На самом деле, pid файл там.
killproc стандартный центосевый (RHEL'овский?), могу привести его код, хотя он для меня тоже почти китайская грамота.
Но скорее, я попытаюсь дописать в инит скрипт что-то, что брало бы пид из пидфайла и этим же килпроцом убивало только этот сабжевый процесс.
 # A function to stop a program.
killproc() {
local RC killlevel= base pid pid_file= delay try binary=

RC=0; delay=3; try=0
# Test syntax.
if [ "$#" -eq 0 ]; then
echo $"Usage: killproc [-p pidfile] [ -d delay] {program} [-signal]"
return 1
fi
if [ "$1" = "-p" ]; then
pid_file=$2
shift 2
fi
if [ "$1" = "-b" ]; then
if [ -z $pid_file ]; then
echo $"-b option can be used only with -p"
echo $"Usage: killproc -p pidfile -b binary program"
return 1
fi
binary=$2
shift 2
fi
if [ "$1" = "-d" ]; then
delay=$(echo $2 | awk -v RS=' ' -v IGNORECASE=1 '{if($1!~/^[0-9.]+[smhd]?$/) exit 1;d=$1~/s$|^[0-9.]*$/?1:$1~/m$/?60:$1~/h$/?60*60:$1~/d$/?24*60*60:-1;if(d==-1) exit 1;delay+=d*$1} END {printf("%d",delay+0.5)}')
if [ "$?" -eq 1 ]; then
echo $"Usage: killproc [-p pidfile] [ -d delay] {program} [-signal]"
return 1
fi
shift 2
fi


# check for second arg to be kill level
[ -n "${2:-}" ] && killlevel=$2

# Save basename.
base=${1##*/}

# Find pid.
__pids_var_run "$1" "$pid_file" "$binary"
RC=$?
if [ -z "$pid" ]; then
if [ -z "$pid_file" ]; then
pid="$(__pids_pidof "$1")"
else
[ "$RC" = "4" ] && { failure $"$base shutdown" ; return $RC ;}
fi
fi

# Kill it.
if [ -n "$pid" ] ; then
[ "$BOOTUP" = "verbose" -a -z "${LSB:-}" ] && echo -n "$base "
if [ -z "$killlevel" ] ; then
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 ; then
try=0
while [ $try -lt $delay ] ; do
checkpid $pid || break
sleep 1
let try+=1
done
if checkpid $pid ; then
kill -KILL $pid >/dev/null 2>&1
usleep 100000
fi
fi
fi
checkpid $pid
RC=$?
[ "$RC" -eq 0 ] && failure $"$base shutdown" || success $"$base shutdown"
RC=$((! $RC))
# use specified level only
else
if checkpid $pid; then
kill $killlevel $pid >/dev/null 2>&1
RC=$?
[ "$RC" -eq 0 ] && success $"$base $killlevel" || failure $"$base $killlevel"
elif [ -n "${LSB:-}" ]; then
RC=7 # Program is not running
fi
fi
else
if [ -n "${LSB:-}" -a -n "$killlevel" ]; then
RC=7 # Program is not running
else
failure $"$base shutdown"
RC=0
fi
fi

# Remove pid file if any.
if [ -z "$killlevel" ]; then
rm -f "${pid_file:-/var/run/$base.pid}"
fi
return $RC
}

Marinavo_0507

Usage: killproc [-p pidfile] [ -d delay] {program} [-signal]
можно попробовать указать pidfile, как предлагают

carusya

Ой, а я почему-то прочитал, что он pid просит, а не pidfile. Сейчас попробую.

carusya

Да, указал pid файл, работает вообще идеально.
ОК, оставлю в таком виде.
Снова спасибо!

Ivan8209

> if [ "$1" = "-p" ]; then
Школьники во всей красе.
---
Q6: Я слышал есть такой мужик, вроде Бармин зовут, и он
придумал что-то такое после чего XXX не сосет.

carusya

Ты про = вместо ==? Там так все условия записаны. Может, формат bash скрипта такой?
Или про if if if вместо case? Так может его нет в bash?

Ivan8209

> Или про if if if вместо case? Так может его нет в bash?
Если там нет "getopts" и "case", то он не соблюдает стандарт.
Да и в целом, идиоматический код через "getopts" и "case" лучше.
---
Q6: Я слышал есть такой мужик, вроде Бармин зовут, и он
придумал что-то такое после чего XXX не сосет.

Ivan8209

> Ты про = вместо ==? Там так все условия записаны. Может, формат bash скрипта такой?
Да, кстати, это я упустил: "=" правильно, а "==" нет. Потому что стандарт.
---
"The last good thing written in C was
Franz Schubert's Symphony Number 9."

Filan

В логах пишет, что как будто в / потому, что в конфиге chroot = /var/run/stunnel. На самом деле, pid файл там.
Проверь где реально расположен pid файл после запуска сервиса.
Есть подозрение, что в /var/run/stunnel/var/run/.
Либо наоборот - кладёт при старте его в /var/run/stunnel, а ищет при стопе в /.
 
chroot keeps stunnel in chrooted jail. CApath, CRLpath, pid and exec are located inside the jail and the patches have to be relative to the directory specified with chroot.

Вот ещё в мане об этом говорится: при старте pid фал пишется в chroot, а при стопе ищется без chroot-а.

carusya

Реально в /var/run/stunnel
Где ищется (без явного указания пути, как сейчас) - не знаю, как проверить.

Ivan8209

Скрипты на шеле (кроме сильно замороченных) отлаживаются методом вставок
"set +x" и "set -x" в интересных местах.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."

carusya

А вывод отладки высыпется мне в консоль?
Их же запускаю не я, а init (в моем случае)

marat7256

Вообще-то скрипты можешь запускать и ты.

carusya

"sh /etc/init.d/stunnel stop"?
Да ладно, забейте, виста найденное решение (с явным указанием pid файла) меня полностью устраивает.
Оставить комментарий
Имя или ник:
Комментарий: