Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1423478
  • 博文数量: 122
  • 博客积分: 340
  • 博客等级: 一等列兵
  • 技术积分: 2967
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-01 11:50
个人简介

说点什么呢

文章分类

全部博文(122)

文章存档

2018年(2)

2017年(1)

2015年(2)

2014年(30)

2013年(81)

2011年(5)

2009年(1)

分类: 系统运维

2013-11-21 15:49:20

sendmail 启动脚本分析

(整理日期:2008-3-5)
(脚本文件环境:RedHat 4 EL / sendmail-8.13.1-3.RHEL4.5 )

一、脚本说是

下列这个脚本是在RedHat 4 EL 下通过service 命令来启动和关闭sendmail shell 脚本,其存放目录在:/etc/init.d/sendmail 文件。该文件的权限是:-rwxr-xr-x

二、脚本逐行分析

#!/bin/bash

#

# sendmail      This shell script takes care of starting and stopping

#               sendmail.

#

# chkconfig: 2345 80 30

# description: Sendmail is a Mail Transport Agent, which is the program \

#              that moves mail from one machine to another.

# processname: sendmail

# config: /etc/mail/sendmail.cf

# pidfile: /var/run/sendmail.pid

以上部分为一些说明

# Source function library.

. /etc/rc.d/init.d/functions

包含 /etc/rc.d/init.d/functions 文件,该文件是系统安装后,系统自带的一个包含常见shell函数的文件。一般众多的shell 脚本程序都使用这个文件,这样可以大大减少编程的工作量。该文件的具体内容见附录部分

# Source networking configuration.

[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network

检查在/etc/sysconfig 下,是否存在network这个文件,如果存在则包含这个文件。而这个文件里包含了网络部分的设置,如是该机器是否启动网络,网关,及主机名。该文件的内容是:

NETWORKING=yes

HOSTNAME=test.smartpay.com.cn

GATEWAY=192.168.1.1

# Source sendmail configureation.

if [ -f /etc/sysconfig/sendmail ] ; then

. /etc/sysconfig/sendmail

else

DAEMON=no

QUEUE=1h

fi

  如果/etc/sysconfig/sendmail 文件存在,则包含这个文件,而这个文件里是定义了两个变量。下面是这个文件里的内容。而如果这个文件不存在,则定义两个变量,DAEMON 和 QUEUE

[ -z "$SMQUEUE" ] && SMQUEUE="$QUEUE"

[ -z "$SMQUEUE" ] && SMQUEUE=1h

#如果变量SMQUEUE为空的,则这个变量的值为$QUEUE变量的值,也就是上面所包含的sendmail配置文件里定义的或者后来定义的。

#同样,下面的一句也是检测SMQUEUE是否为空,如果为空则将这个变量的值设置成1h。之所以两次对这个变量进行判断,是因为防止因为/etc/sysconfig/sendmail 文件存在,而该文件中又没有定义这个变量,也就是保证这个变量一定要有值

# Check that networking is up.

[ "${NETWORKING}" = "no" ] && exit 0

检测当前这台机器的网络功能是否已经启动,如果没有,则退出这个脚本的运行。因为连网络都没有启用,则启动sendmail 没有什么意义

"${NETWORKING}" 就是在/etc/sysconfig/network文件中定义的一个选项

[ -f /usr/sbin/sendmail ] || exit 0

如果/usr/sbin/sendmail这个文件不存在,则退出脚本的继续执行。在实际系统中这个文件是一个连接文件。lrwxrwxrwx  1 root root 21 Feb 18 15:50 /usr/sbin/sendmail -> /etc/alternatives/mta

RETVAL=0

prog="sendmail"

start() {

定义start 函数

# Start daemons.

echo -n $"Starting $prog: "

在屏幕上显示出 Starting sendmail 字样,这里的 是表示下面的信息也在一行来显示,之所以带这个参数,所以在系统启动时就会出现”Starting sendmail: [  OK  ] 的信息出来。要知道这个显示里的 Starting sendmail:和后面的[  OK  ]是在不同的时候显示的。

if test -x /usr/bin/make -a -f /etc/mail/Makefile ; then

  make all -C /etc/mail -s > /dev/null

如果 /usr/bin/make的文件属性为可执行,且在/etc/mail下有 Makefile文件,则编译 /etc/mail下的所有文件。这是将sendmail的配置文件在启动的时候都重新编译一下。

else

  for i in virtusertable access domaintable mailertable ; do

    if [ -f /etc/mail/$i ] ; then

makemap hash /etc/mail/$i < /etc/mail/$i

    fi

  done

fi

如果上述条件不成立,则使用循环语句,分别对/etc/mail下的virtusertableaccess domaintablemailertable生成相应的db文件。

/usr/bin/newaliases > /dev/null 2>&1

执行/usr/bin/newaliases 命令,且将输出的信息屏蔽掉。关于 2>&1说明如下:

POSIX shell中,命令的结果可以通过%>的形式来定义(其中%表示文件描述符: 为标准备输入,1为标准输出stdout2为标准错误stderr)!系统默认值是1,也就是1>,而1>可以 简写为>,也就是默认为>

例如:有以下两个文件:

aaa.sh 文件内容

#!/bin/sh

cat bbb.sh

cat aaaaa.sh

        bbb.sh 文件内容

#!/bin/sh

for i in aaa bbb ccc ; do

         echo -n $i;

    done

       aaaaa.sh 不存在,当直接执行如下命令则有:

./aaa.sh 

#!/bin/sh

for i in aaa bbb ccc ; do

         echo -n $i;

done

cat: aaaaa.sh: No such file or directory

这时候正常内容和错误信息都显示在屏幕上,当使用下列命令时则有:

./aaa.sh 2>/dev/null  

#!/bin/sh

for i in aaa bbb ccc ; do

         echo -n $i;

done

注意:这时候不显示错误信息了,这是因为错误信息被输出到标准输入2上之后又 没有被重新定向到了 /dev/null 下了

而使用下列命令时则有:

./aaa.sh >/dev/null  

cat: aaaaa.sh: No such file or directory

注意:这时候只输出错误的信息了。这是因为标准的输出被重定向了 /dev/null下了。而标准输出1是系统默认的,可以省略的,以上命令等于如下命令:

./aaa.sh  1>/dev/null

    而当使用下列命令时,则什么信息也没有显示出来,./aaa.sh >/dev/null 2>&1

之所以什么显示也没有,是因为标准输出被重定向到了 /dev/null下了,而标准错误输出又被得定向到了标准备输出了,所以什么都没有显示出来了。

daemon /usr/sbin/sendmail $([ "x$DAEMON" = xyes ] && echo -bd) \

$([ -n "$QUEUE" ] && echo -q$QUEUE) $SENDMAIL_OPTARG

RETVAL=$?

使用function 脚本文件里的定义的daemon函数来启动sendmail 服务,其中先判断DAEMON变量的值是不是yes,如果是yes 则在命令的后面添加上 bd选项,同时判断 QUEUE变量是不是为空,如果不为空,则带上这个选项并加上-q这个选项,最后加上ENDMAIL_OPTARG变量指定的选项。

echo

提示信息换行

[ $RETVAL -eq 0 ] && touch /var/lock/subsys/sendmail

如果启动正常,则在 /var/lock/subsys目录下生成一个 sendmail 空文件,这个文件跟/var/run下的sendmail.pic文件来标识sendmail服务器已经在运行.

if ! test -f /var/run/sm-client.pid ; then

echo -n $"Starting sm-client: "

touch /var/run/sm-client.pid

chown smmsp:smmsp /var/run/sm-client.pid

if [ -x /usr/bin/selinuxenabled ] && /usr/bin/selinuxenabled; then

    /sbin/restorecon /var/run/sm-client.pid

fi

daemon --check sm-client /usr/sbin/sendmail -L sm-msp-queue -Ac \

-q $SMQUEUE $SENDMAIL_OPTARG

RETVAL=$?

        echo

        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/sm-client

        fi

return $RETVAL

}

上述这段代码与启动sendmail服务的代码类似,可以比照来看。

reload() {

定义重启函数

# Stop 

     echo -n $"reloading $prog: "     打印出重启服务信息

/usr/bin/newaliases > /dev/null 2>&1   

if [ -x /usr/bin/make -a -f /etc/mail/Makefile ]; then

  make all -C /etc/mail -s > /dev/null

else

  for i in virtusertable access domaintable mailertable ; do

    if [ -f /etc/mail/$i ] ; then

makemap hash /etc/mail/$i < /etc/mail/$i

    fi

  done

fi

daemon /usr/sbin/sendmail $([ "x$DAEMON" = xyes ] && echo -bd) \

    $([ -n "$QUEUE" ] && echo -q$QUEUE)

RETVAL=$?

killproc sendmail –HUP 

RETVAL=$?

echo

if [ $RETVAL -eq 0 -a -f /var/run/sm-client.pid ]; then

echo -n $"reloading sm-client: "

killproc sm-client -HUP

RETVAL=$?

echo

fi

return $RETVAL

}

上述的语句与start函数的类似,可以对比着查看

stop() {     定义stop 函数

# Stop daemons.

echo -n $"Shutting down $prog: "

killproc sendmail

RETVAL=$?

echo

[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/sendmail

if test -f /var/run/sm-client.pid ; then

echo -n $"Shutting down sm-client: "

killproc sm-client

RETVAL=$?

echo

[ $RETVAL -eq 0 ] && rm -f /var/run/sm-client.pid

[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/sm-client

fi

return $RETVAL

}

 #  上述语句与start函数中的语句对比看,比较容易懂

# See how we were called.

   # 根据输入的第1个参数来确定调用函数;

case "$1" in

  start)

start

;;

  stop)

stop

;;

  reload)

reload

RETVAL=$?

;;

  restart)

stop

start

RETVAL=$?

;;

  condrestart)

if [ -f /var/lock/subsys/sendmail ]; then

    stop

    start

    RETVAL=$?

fi

;;

  status)

status sendmail

RETVAL=$?

;;

  *)

echo $"Usage: $0 {start|stop|restart|condrestart|status}"

exit 1

esac

exit $RETVAL

三、function脚本文件内容

# -*-Shell-script-*-

#

# functions This file contains functions to be used by most or all

# shell scripts in the /etc/init.d directory.

#

TEXTDOMAIN=initscripts

# Make sure umask is sane

umask 022

# Set up a default search path.

PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"

export PATH

# Get a sane screen width

[ -z "${COLUMNS:-}" ] && COLUMNS=80

[ -z "${CONSOLETYPE:-}" ] && CONSOLETYPE="`/sbin/consoletype`"

if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then

  . /etc/sysconfig/i18n

  if [ "$CONSOLETYPE" != "pty" ]; then

case "${LANG:-}" in

ja_JP*|ko_KR*|zh_CN*|zh_TW*|bn_*|bd_*|pa_*|hi_*|ta_*|gu_*)

export LC_MESSAGES=en_US

export LANG

;;

*)

export LANG

;;

esac

  else

   [ -n "$LC_MESSAGES" ] && export LC_MESSAGES

export LANG

  fi

fi

# Read in our configuration

if [ -z "${BOOTUP:-}" ]; then

  if [ -f /etc/sysconfig/init ]; then

      . /etc/sysconfig/init

  else

    # This all seem confusing? Look in /etc/sysconfig/init,

    # or in /usr/doc/initscripts-*/sysconfig.txt

    BOOTUP=color

    RES_COL=60

    MOVE_TO_COL="echo -en \\033[${RES_COL}G"

    SETCOLOR_SUCCESS="echo -en \\033[1;32m"

    SETCOLOR_FAILURE="echo -en \\033[1;31m"

    SETCOLOR_WARNING="echo -en \\033[1;33m"

    SETCOLOR_NORMAL="echo -en \\033[0;39m"

    LOGLEVEL=1

  fi

  if [ "$CONSOLETYPE" = "serial" ]; then

      BOOTUP=serial

      MOVE_TO_COL=

      SETCOLOR_SUCCESS=

      SETCOLOR_FAILURE=

      SETCOLOR_WARNING=

      SETCOLOR_NORMAL=

  fi

fi

if [ "${BOOTUP:-}" != "verbose" ]; then

   INITLOG_ARGS="-q"

else

   INITLOG_ARGS=

fi

# Check if $pid (could be plural) are running

checkpid() {

local i

for i in $* ; do

[ -d "/proc/$i" ] && return 0

done

return 1

}

# 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"

}

# A function to stop a program.

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##*/}

        echo "base value is:"$base

        # 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

}

# A function to find the pid of a program. Looks *only* at the pidfile

pidfileofproc() {

local base=${1##*/}

# Test syntax.

if [ "$#" = 0 ] ; then

echo $"Usage: pidfileofproc {program}"

return 1

fi

# First try "/var/run/*.pid" files

if [ -f /var/run/$base.pid ] ; then

        local line p pid=

read line < /var/run/$base.pid

for p in $line ; do

       [ -z "${p//[0-9]/}" -a -d /proc/$p ] && pid="$pid $p"

done

        if [ -n "$pid" ]; then

                echo $pid

                return 0

        fi

fi

}

# A function to find the pid of a program.

pidofproc() {

base=${1##*/}

# Test syntax.

if [ "$#" = 0 ]; then

echo $"Usage: pidofproc {program}"

return 1

fi

# First try "/var/run/*.pid" files

if [ -f /var/run/$base.pid ]; then

        local line p pid=

read line < /var/run/$base.pid

for p in $line ; do

       [ -z "${p//[0-9]/}" -a -d /proc/$p ] && pid="$pid $p"

done

        if [ -n "$pid" ]; then

                echo $pid

                return 0

        fi

fi

pidof -o $$ -o $PPID -o %PPID -x $1 || \

pidof -o $$ -o $PPID -o %PPID -x $base

}

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

}

echo_success() {

  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL

  echo -n "[  "

  [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS

  echo -n $"OK"

  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

  echo -n "  ]"

  echo -ne "\r"

  return 0

}

echo_failure() {

  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL

  echo -n "["

  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE

  echo -n $"FAILED"

  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

  echo -n "]"

  echo -ne "\r"

  return 1

}

echo_passed() {

  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL

  echo -n "["

  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING

  echo -n $"PASSED"

  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

  echo -n "]"

  echo -ne "\r"

  return 1

}

echo_warning() {

  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL

  echo -n "["

  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING

  echo -n $"WARNING"

  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

  echo -n "]"

  echo -ne "\r"

  return 1

}

# Inform the graphical boot of our current state

update_boot_stage() {

  if [ "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb-client ]; then

    /usr/bin/rhgb-client --update="$1"

  fi

  return 0

}

# Log that something succeeded

success() {

  if [ -z "${IN_INITLOG:-}" ]; then

     initlog $INITLOG_ARGS -n $0 -s "$1" -e 1

  else

     # silly hack to avoid EPIPE killing rc.sysinit

     trap "" SIGPIPE

     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21

     trap - SIGPIPE

  fi

  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_success

  return 0

}

# Log that something failed

failure() {

  rc=$?

  if [ -z "${IN_INITLOG:-}" ]; then

     initlog $INITLOG_ARGS -n $0 -s "$1" -e 2

  else

     trap "" SIGPIPE

     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 2" >&21

     trap - SIGPIPE

  fi

  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_failure

  [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes

  return $rc

}

# Log that something passed, but may have had errors. Useful for fsck

passed() {

  rc=$?

  if [ -z "${IN_INITLOG:-}" ]; then

     initlog $INITLOG_ARGS -n $0 -s "$1" -e 1

  else

     trap "" SIGPIPE

     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21

     trap - SIGPIPE

  fi

  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_passed

  return $rc

}  

# Log a warning

warning() {

  rc=$?

  if [ -z "${IN_INITLOG:-}" ]; then

     initlog $INITLOG_ARGS -n $0 -s "$1" -e 1

  else

     trap "" SIGPIPE

     echo "$INITLOG_ARGS -n $0 -s \"$1\" -e 1" >&21

     trap - SIGPIPE

  fi

  [ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_warning

  return $rc

}  

# Run some action. Log its output.

action() {

  STRING=$1

  echo -n "$STRING "

  if [ "${RHGB_STARTED}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then

      echo -n "$STRING " > /etc/rhgb/temp/rhgb-console

  fi

  shift

  initlog $INITLOG_ARGS -c "$*" && success $"$STRING" || failure $"$STRING"

  rc=$?

  echo

  if [ "${RHGB_STARTED}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then

      if [ "$rc" = "0" ]; then

       echo_success > /etc/rhgb/temp/rhgb-console

      else

        echo_failure > /etc/rhgb/temp/rhgb-console

[ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes

      fi

      echo

  fi

  return $rc

}

# returns OK if $1 contains $2

strstr() {

  [ "${1#*$2*}" = "$1" ] && return 1

  return 0

}

# Confirm whether we really want to run this service

confirm() {

  [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes

  while : ; do 

      echo -n $"Start service $1 (Y)es/(N)o/(C)ontinue? [Y] "

      read answer

      if strstr $"yY" "$answer" || [ "$answer" = "" ] ; then

         return 0

      elif strstr $"cC" "$answer" ; then

 rm -f /var/run/confirm

 [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=no

         return 2

      elif strstr $"nN" "$answer" ; then

         return 1

      fi

  done

}

阅读(3248) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~