Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org

Управление демонами с помощью init scripts

Когда вы ставите новый стандартный дистрибутив , подчас все необходимые демоны вы можете выставить в процессе инсталляции . Но как быть , если вы ставите систему с нуля и нет никаких init-скриптов ? В этой статье вы можете найти несколько способов решения этой проблемы .

Можно управлять инициализацией несколькими способами . Один из путей - поместить команды для запуска демонов в файл /etc/rc.d/rc.local. Этот метод очень прост . Но в большинстве стандартных систем инициализация демонов так не делается .

Можно в rc.local вызвать какой-то другой скрипт . Вообще этот метод несколько топорный , и у него не хватает гибкости .

Другой способ - запустить демона из файла /etc/inittab . Эту технику некоторые используют , но я бы не советовал ее использовать , особенно в случае одновременной поддержки нескольких серверов .

В этом случае каждым конкретным демоном возможно будет управлять лишь из командной строки. И к тому же управляемость системой на уровне знания inittab - это не очень хорошая идея.

Init-скрипты дают админу возможность эффективно управлять ресурсами системы в плане запуска-останова демонов . В init-скриптах стандартных дистрибутивов управление демонами по возможности максимально упрощена . В таких системах управление отдельным демоном - достаточно прозрачное занятие.

Давайте приступим к созданию init script. Вы убедитесь в том , насколько легок этот процесс , и обнаружите при этом функциональность , ранее вам неизвестную .

Создание init script

Я собираюсь сделать обзор , основанный на реальном опыте . Я использую Fedora Directory Server. Вначале я скачал и проинсталлировал бинарные RPM-пакеты и протестировал их работу. Следующий шаг - проверка их комплексной системной работоспособности .

Я создал собственный init-скрипт. Сначала я занялся поиском шаблона . Если вы знаете , что ваш демон зависит от другого демона , вы можете использовать init-скрипт для этого демона в качестве шаблона. В вашем дистрибутиве в каталоге /usr/share/doc/initscript.../ должен лежать файл sysvinitfiles. Из него я взял следующий кусок :

#!/bin/bash
 #
 #       /etc/rc.d/init.d/
 #
 #
 #
 #
 #
 
 # Source function library.
 . /etc/init.d/functions
 
 
 
 start() {
         echo -n "Starting : "
 
         touch /var/lock/subsys/
         return
 }
 
 stop() {
         echo -n "Shutting down : "
 
         rm -f /var/lock/subsys/
         return
 }
 
 case "$1" in
     start)
         start
         ;;
     stop)
         stop
         ;;
     status)
 
         ;;
     restart)
         stop
         start
         ;;
     reload)
 
 tart)
 
         [ -f /var/lock/subsys/ ] && restart || :
     probe)
 
         ;;
     *)
         echo "Usage:  {start|stop|status|reload|restart[|probe]"
         exit 1
         ;;
 esac
 exit $?
 

Как вы видите , весь код находится в одном месте , с пустыми пока телами для наполнения функций .

Яковлев С : А для 3-й федоры файл /usr/share/doc/initscript.../sysvinitfiles выглядит так :

 Writing System V init scripts for Red Hat Linux
 ===============================================
 
 All System V init scripts are named /etc/rc.d/init.d/
 where  is the name of the service.  There must be no
 ".init" suffix.
 
 This path will very likely be moved to /etc/init.d in the future.
 Once Red Hat Linux 7.0 is installed, you can access scripts as
 /etc/init.d/, via symlinks.
 
 Sample Script
 =============
 
 #!/bin/bash
 #
 #	/etc/rc.d/init.d/
 #
 #	
 #	
 #
 # 
 
 # Source function library.
 . /etc/init.d/functions
 
 
 
 start() {
 	echo -n "Starting : "
 	
 	touch /var/lock/subsys/
 	return 
 }	
 
 stop() {
 	echo -n "Shutting down : "
 	
 	rm -f /var/lock/subsys/
 	return 
 }
 
 case "$1" in
     start)
 	start
 	;;
     stop)
 	stop
 	;;
     status)
 	
 	;;
     restart)
     	stop
 	start
 	;;
     reload)
 	
 	;;
     condrestart)
     	
 	[ -f /var/lock/subsys/ ] && restart || :
     probe)
 	
 	;;
     *)
 	echo "Usage:  {start|stop|status|reload|restart[|probe]"
 	exit 1
 	;;
 esac
 exit $?
 
 Notes: 
 
 - The restart and reload functions may be (and commonly are)
   combined into one test, vis:
     restart|reload)
 - You are not prohibited from adding other commands; list all commands
   which you intend to be used interactively to the usage message.
 - Notice the change in that stop() and start() are now shell functions.
   This means that restart can be implemented as
      stop
      start
   instead of
      $0 stop
      $0 start
   This saves a few shell invocations.
 
 Functions in /etc/init.d/functions
 =======================================
 
 daemon  [ --check  ] [ --user ] 
 	[+/-nicelevel] program [arguments] [&]
 
 	Starts a daemon, if it is not already running.  Does
 	other useful things like keeping the daemon from dumping
 	core if it terminates unexpectedly.
 	
 	--check :
 	   Check that  is running, as opposed to simply the
 	   first argument passed to daemon().
 	--user :
 	   Run command as user 
 
 killproc program [signal]
 
 	Sends a signal to the program; by default it sends a SIGTERM,
 	and if the process doesn't die, it sends a SIGKILL a few
 	seconds later.
 
 	It also tries to remove the pidfile, if it finds one.
 
 pidofproc program
 
 	Tries to find the pid of a program; checking likely pidfiles,
 	and using the pidof program.  Used mainly from within other
 	functions in this file, but also available to scripts.
 
 status program
 
 	Prints status information.  Assumes that the program name is
 	the same as the servicename.
 
 
 Tags
 ====
 
 # chkconfig:   
 
 	Required.   is a list of levels in which
 	the service should be started by default.  
 	and  are priority numbers.  For example:
 	# chkconfig: 2345 20 80
 	Read 'man chkconfig' for more information.
 
 	Unless there is a VERY GOOD, EXPLICIT reason to the
 	contrary, the  should be equal to
 	100 - 
 	
 # description: 
 
 	Required.  Several lines of description, continued with '\'
 	characters.  The initial comment and following whitespace
 	on the following lines is ignored.
 
 # description[ln]: 
 
 	Optional.  Should be the description translated into the
 	specified language.
 
 # processname:
 
 	Optional, multiple entries allowed.  For each process name
 	started by the script, there should be a processname entry.
 	For example, the samba service starts two daemons:
 	# processname: smdb
 	# processname: nmdb
 
 # config:
 
 	Optional, multiple entries allowed.  For each static config
 	file used by the daemon, use a single entry.  For example:
 	# config: /etc/httpd/conf/httpd.conf
 	# config: /etc/httpd/conf/srm.conf
 
 	Optionally, if the server will automatically reload the config
 	file if it is changed, you can append the word "autoreload" to
 	the line:
 	# config: /etc/foobar.conf autoreload
 
 # pidfile:
 
 	Optional, multiple entries allowed.  Use just like the config
 	entry, except that it points at pidfiles.  It is assumed that
 	the pidfiles are only updated at process creation time, and
 	not later.  The first line of this file should be the ASCII
 	representation of the PID; a terminating newline is optional.
 	Any lines other than the first line are not examined.
 
 # probe: true
 
 	Optional, used IN PLACE of processname, config, and pidfile.
 	If it exists, then a proper reload-if-necessary cycle may be
 	acheived by running these commands:
 
 	command=$(/etc/rc.d/init.d/SCRIPT probe)
 	[ -n "$command" ] && /etc/rc.d/init.d/SCRIPT $command
 
 	where SCRIPT is the name of the service's sysv init script.
 
 	Scripts that need to do complex processing could, as an
 	example, return "run /var/tmp/
 

Обратите внимание вверху скрипта на ссылку на файл /etc/init.d/functions. В нем находятся bash shell - функции . Обязательно изучите этот файл , и вы поймете , как и почему случаются ошибки во время запуска или останова .

Яковлев С : Вот фрагмент из /etc/init.d/functions для 3-й федоры :

 # -*-Shell-script-*-
 #
 # functions	This file contains functions to be used by most or all
 #		shell scripts in the /etc/init.d directory.
 #
 
 killproc() {
 	RC=0
 	# Test syntax.
 	if [ "$#" -eq 0 ]; then
 		echo $"Usage: killproc {program} [signal]"
 		return 1
 	fi
 
 	notset=0
 	# check for second arg to be kill level
 	if [ -n "$2" ]; then
 		killlevel=$2
 	else
 		notset=1
 		killlevel="-9"
 	fi
 
         # Save basename.
         base=${1##*/}
 
         # Find pid.
 	pid=
 	if [ -f /var/run/${base}.pid ]; then
 		local line p
 		read line < /var/run/${base}.pid
 		for p in $line ; do
 			[ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"
 		done
 	fi
 	if [ -z "$pid" ]; then
 		pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || \
 			pidof -o $$ -o $PPID -o %PPID -x $base`
 	fi
 
         # Kill it.
         if [ -n "${pid:-}" ] ; then
 [ "$BOOTUP" = "verbose" -a -z "$LSB" ] && echo -n "$base "
 if [ "$notset" -eq "1" ] ; 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 && sleep 1 &&
                 checkpid $pid && sleep 3 &&
                 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"
         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"
 fi
 fi
 	else
 	    failure $"$base shutdown"
 	    RC=1
 	fi
 
         # Remove pid file if any.
 	if [ "$notset" = "1" ]; then
             rm -f /var/run/$base.pid
 	fi
 	return $RC
 }
 
 status() {
 	local base=${1##*/}
 	local pid
 
 	# Test syntax.
 	if [ "$#" = 0 ] ; then
 		echo $"Usage: status {program}"
 		return 1
 	fi
 
 	# First try "pidof"
 	pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || \
 	     pidof -o $$ -o $PPID -o %PPID -x ${base}`
 	if [ -n "$pid" ]; then
 	        echo $"${base} (pid $pid) is running..."
 	        return 0
 	fi
 
 	# Next try "/var/run/*.pid" files
 	if [ -f /var/run/${base}.pid ] ; then
 	        read pid < /var/run/${base}.pid
 	        if [ -n "$pid" ]; then
 	                echo $"${base} dead but pid file exists"
 	                return 1
 	        fi
 	fi
 	# See if /var/lock/subsys/${base} exists
 	if [ -f /var/lock/subsys/${base} ]; then
 		echo $"${base} dead but subsys locked"
 		return 2
 	fi
 	echo $"${base} is stopped"
 	return 3
 }
 # A function to start a program.
 daemon() {
 	# Test syntax.
 	local gotbase= force=
 	local base= user= nice= bg= pid=
 	nicelevel=0
 	while [ "$1" != "${1##[-+]}" ]; do
 	  case $1 in
 	    '')    echo $"$0: Usage: daemon [+/-nicelevel] {program}"
 	           return 1;;
 	    --check)
 		   base=$2
 		   gotbase="yes"
 		   shift 2
 		   ;;
 	    --check=?*)
 	    	   base=${1#--check=}
 		   gotbase="yes"
 		   shift
 		   ;;
 	    --user)
 		   user=$2
 		   shift 2
 		   ;;
 	    --user=?*)
 	           user=${1#--user=}
 		   shift
 		   ;;
 	    --force)
 	    	   force="force"
 		   shift
 		   ;;
 	    [-+][0-9]*)
 	    	   nice="nice -n $1"
 	           shift
 		   ;;
 	    *)     echo $"$0: Usage: daemon [+/-nicelevel] {program}"
 	           return 1;;
 	  esac
 	done
 
         # Save basename.
         [ -z "$gotbase" ] && base=${1##*/}
 
         # See if it's already running. Look *only* at the pid file.
 	if [ -f /var/run/${base}.pid ]; then
 		local line p
 		read line < /var/run/${base}.pid
 		for p in $line ; do
 			[ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"
 		done
 	fi
 	
 	[ -n "${pid:-}" -a -z "${force:-}" ] && return
 
 	# make sure it doesn't core dump anywhere unless requested
 	ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0} >/dev/null 2>&1
 	
 	# if they set NICELEVEL in /etc/sysconfig/foo, honor it
 	[ -n "$NICELEVEL" ] && nice="nice -n $NICELEVEL"
 	
 	# Echo daemon
         [ "${BOOTUP:-}" = "verbose" -a -z "$LSB" ] && echo -n " $base"
 
 	# And start it up.
 	if [ -z "$user" ]; then
 	   $nice initlog $INITLOG_ARGS -c "$*"
 	else
 	   $nice initlog $INITLOG_ARGS -c "runuser -s /bin/bash - $user -c \"$*\""
 	fi
 	[ "$?" -eq 0 ] && success $"$base startup" || failure $"$base startup"
 }
 
 
 

А вот и сам скрипт , ради которого и написана эта статья :


 
 #!/bin/bash
 #
 #       /etc/rc.d/init.d/ns-slapd
 # ns-slapd      This shell script takes care of starting and stopping
 #               ns-slapd (the Fedora Directory Server)
 #
 # Author: Brian Jones jonesy@cs.princeton.edu
 #
 # chkconfig: 2345 13 87
 # description: ns-slapd is the Fedora Directory Service daemon. \
 # FDS can serve as a repository for (and, subsequently, a source of) \
 # data for most of the resources listed in /etc/nsswitch.conf, such as \
 # passwd or group entries.
 
 # Source function library.
 . /etc/init.d/functions
 
 SLAPD_HOST=`hostname -a`
 SLAPD_DIR=/opt/fedora-ds/bin/slapd/server
 PIDFILE=$SLAPD_DIR/logs/pid
 STARTPIDFILE=$SLAPD_DIR/logs/startpid
 
 if [ -f /etc/sysconfig/ns-slapd ]; then
         . /etc/sysconfig/ns-slapd
 fi
 
 
 start() {
         echo -n "Starting Fedora Directory Server: "
         if [ -f $STARTPIDFILE ]; then
                 PID=`cat $STARTPIDFILE`
                 echo ns-slapd already running: $PID
                 exit 2;
         elif [ -f $PIDFILE ]; then
                 PID=`cat $PIDFILE`
                 echo ns-slapd already running: $PID
                 exit 2;
         else
                 cd $SLAPD_DIR
                 daemon  ./ns-slapd $OPTIONS
                 RETVAL=$?
                 echo
                 [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ns-slapd
                 return $RETVAL
         fi
 
 }
 
 stop() {
         echo -n "Shutting down Fedora Directory Server: "
         echo
         killproc ns-slapd
         echo
         rm -f /var/lock/subsys/ns-slapd
         return 0
 }
 
 case "$1" in
     start)
         start
         ;;
     stop)
         stop
         ;;
     status)
         status ns-slapd
         ;;
     restart)
         stop
         start
         ;;
     *)
         echo "Usage:  {start|stop|status|restart}"
         exit 1
         ;;
 esac
 exit $?
 
 

В этом скрипте используются 3 функции : killproc, status, и daemon. Как говорят в таких случаях - вы должны отдавать себе отчет в том , что вы делаете , когда используете эти функции . К примеру , функция , которая пытается получить PID процесса, pidofproc, подразумевает , что pid-файл уже находится где-то в /var/run.

Несколько слов о конфиге /etc/sysconfig/ns-slapd. Он может быть использован для передачи параметров запускаемому демону. Этот файл включает единственную строку :
OPTIONS="-D /opt/fedora-ds/slapd-ldap -i /opt/fedora-ds/slapd-ldap/logs/pid -w /opt/fedora-ds/slapd-ldap/logs/startpid".
Она добавляется в конец команды , запускающей какого-то конкретного демона .
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье