シャットダウンプロセス

起動プロセスをより深く知るためには、シャットダウンプロセスの理解が必要不可欠です。Linux を終了する場合、単に電源を切ることは許されません。単に電源を切ると、深刻な問題をシステムに与えます。

正しいシャットダウンは shutdown プログラムによって行われます。shutdown プログラムの主な役割は シャットダウンをユーザに通知することと、init プログラムにランレベルの変更を依頼することです。

以下のコマンドを実行した場合について説明します。

bash# shutdown -h now

オプション -h は、シャットダウン後にシステムを停止することを指示します。now は、直ちにシャットダウン処理を行うことを指示します。

まず、shutdown プログラムは、ログインしているユーザにシャットダウンを通知します。そして、init プログラムにランレベルを 0 へ変更するように依頼します。ランレベル 0 は電源遮断状態を表します。

依頼を受けた init プログラムは、すべてのプロセスに SIGTERM、SIGKILL の順でシグナルを送ります。これにより、すべてのプロセスは終了します。そして、/etc/inittab に基づき /etc/rc.d/rc.0 を実行します。

/etc/rc.d/rc.0
# Set the path.
PATH=/sbin:/etc:/bin:/usr/bin

コマンドを検索するパスを設定します。

/etc/rc.d/rc.0
# If there are SystemV init scripts for this runlevel, run them.
if [ -x /etc/rc.d/rc.sysvinit ]; then
  . /etc/rc.d/rc.sysvinit
fi

/etc/rc.d/rc.sysvinit が実行可能であれば、/etc/rc.d/rc.sysvinit を実行します。

/etc/rc.d/rc.0
# Set linefeed mode to avoid staircase effect.
stty onlcr

stty onlcr を実行します。これは、表示が階段状になるのを防ぐための端末設定です。

/etc/rc.d/rc.0
# Find out how we were called.
case "$0" in
	*0)
		command="halt"
		;;
	*6)
		command=reboot
		;;
	*)
		echo "$0: call me as ¥"rc.0¥" or ¥"rc.6¥" please!"
		exit 1
		;;
esac

/etc/rc.d/rc.0 は /etc/rc.d/rc.6 へのシンボリックリンクです。すなわち、rc.0 として実行される場合と、rc.6 として実行される場合があります。ここではそれを判別し、rc.0 として実行された場合は、シェル変数 command を "halt" と設定します。rc.6 として実行された場合は、シェル変数 command を reboot と設定します。それら以外の場合は、実行を中止します。

/etc/rc.d/rc.0
# Save the system time to the hardware clock using hwclock --systohc.
# Detect SGI Visual Workstation, since hwclock will make those freeze up:
if fgrep -l Cobalt-APIC /proc/interrupts 1> /dev/null 2> /dev/null ; then
  echo "SGI Visual Workstation detected.  Not running hwclock."
elif [ -x /sbin/hwclock ]; then
  if grep "^UTC" /etc/hardwareclock 1> /dev/null 2> /dev/null ; then
    echo "Saving system time to the hardware clock (UTC)."
    /sbin/hwclock --utc --systohc
  else
    echo "Saving system time to the hardware clock (localtime)."
    /sbin/hwclock --localtime --systohc
  fi
fi

ハードウェア時計を設定します。但し、SGI Visual Workstation であることを検出した場合は、何もしません。/sbin/hwclock が実行可能であれば、/etc/hardwareclock を検査します。UTC と記載されている場合は、/sbin/hwclock --utc --systohc を実行します。UTC と記載されていなければ、/sbin/hwclock --localtime --systohc を実行します。

/etc/rc.d/rc.0
# Stop the Samba server:
if [ -x /etc/rc.d/rc.samba ]; then
  . /etc/rc.d/rc.samba stop
fi

/etc/rc.d/rc.samba が実行可能であれば、/etc/rc.d/rc.samba stop を実行します。これは、Samba を終了します。

/etc/rc.d/rc.0
# Shut down the NFS server:
if [ -x /etc/rc.d/rc.nfsd ]; then
  /etc/rc.d/rc.nfsd stop
fi

/etc/rc.d/rc.nfsd が実行可能であれば、/etc/rc.d/rc.nfsd stop を実行します。これは、NFS サーバを終了します。

/etc/rc.d/rc.0
# Unmount any NFS or SMB filesystems:
echo "Unmounting remote filesystems."
umount -a -r -t nfs,smbfs

umount -a -r -t nfs,smbfs を実行します。これは、NFS と SMB ファイルシステムをアンマウントします。アンマウントに失敗した場合は、読み取り専用で再マウントします。

/etc/rc.d/rc.0
# Shut down PCMCIA devices:
if [ -x /etc/rc.d/rc.pcmcia ] ; then
  . /etc/rc.d/rc.pcmcia stop
  # The cards might need a little extra time here to initialize.
  sleep 5
fi

/etc/rc.d/rc.pcmcia が実行可能であれば、/etc/rc.d/rc.pcmcia stop を実行します。これは、PCMCIA デバイスを終了します。また、初期化に時間がかかるため 5 秒待ちます。

/etc/rc.d/rc.0
# Kill all processes.
# INIT is supposed to handle this entirely now, but this didn't always
# work correctly without this second pass at killing off the processes.
# Since INIT already notified the user that processes were being killed,
# we'll avoid echoing this info this time around.
if [ "$1" != "fast" ]; then # shutdown did not already kill all processes
  killall5 -15 
  sleep 5
  killall5 -9
fi

すべてのプロセスに、SIGTERM、SIGKILL の順でシグナルを送ります。これは、すでに init プログラムによって行われていますが、念のためにもう一度ここで行います。

/etc/rc.d/rc.0
# Try to turn off quota:
if fgrep quota /etc/fstab 1> /dev/null 2> /dev/null ; then
  if [ -x /sbin/quotaoff ]; then
    echo "Turning off filesystem quotas."
    /sbin/quotaoff -a
  fi
fi

/etc/fstab を読み込み、Quota が使われていることを検出した場合、/sbin/quotaoff を調べます。/sbin/quotaoff が実行可能であれば、/sbin/quotaoff -a を実行します。

/etc/rc.d/rc.0
# Before unmounting file systems write a reboot or halt record to wtmp.
$command -w

$command -w を実行します。これは、ファイルシステムをアンマウントする前に wtmp を更新するために実行します。

/etc/rc.d/rc.0
# Carry a random seed between reboots.
# Save 512 bytes, which is the size of the entropy pool.
echo "Saving random seed from /dev/urandom in /etc/random-seed."
dd if=/dev/urandom of=/etc/random-seed count=1 bs=512 2> /dev/null

dd if=/dev/urandom of=/etc/random-seed count=1 bs=512 2> /dev/null を実行します。これは、より良い乱数を発生させるための仕組みです。

/etc/rc.d/rc.0
# Clear /var/lock/subsys.
if [ -d /var/lock/subsys ]; then
  rm -f /var/lock/subsys/*
fi

/var/lock/subsys がディレクトリであれば、rm -f /var/lock/subsys/* を実行します。これは、/var/lock/subsys/ 内のファイルをすべて削除します。

/etc/rc.d/rc.0
# Turn off swap, then unmount local file systems.
echo "Turning off swap."
swapoff -a
echo "Unmounting local file systems."
# Don't remount UMSDOS root volumes:
if [ ! "`mount | head -1 | cut -d ' ' -f 5`" = "umsdos" ]; then
  umount -a -r -t nonfs
  echo "Remounting root filesystem read-only."
  mount -n -o remount,ro /
else
  umount -a -r -t nonfs,noumsdos,nosmbfs
fi

スワッピングを無効にします。次に、ルートファイルシステムを調べます。ファイルシステムが UMSDOS であれば、ルートファイルシステム以外をアンマウントします。ファイルシステムが UMSDOS でない場合は、すべてのファイルシステムをアンマウントし、ルートファイルシステムを読み取り専用で再マウントします。

/etc/rc.d/rc.0
# This never hurts:
sync

sync を実行します。

/etc/rc.d/rc.0
# If we're using LVM, we need to deactivate the volume groups:
if [ -r /etc/lvmtab ]; then
  /sbin/vgchange -an
fi

/etc/lvmtab が読み込み可能であれば、/sbin/vgchange -an を実行します。

/etc/rc.d/rc.0
# sleep 1 fixes problems with some hard drives that don't
# otherwise finish syncing before reboot or poweroff
sleep 1

1 秒待ちます。

/etc/rc.d/rc.0
# This is to ensure all processes have completed on SMP machines:
wait

すべてのプロセスの終了を待ちます。

/etc/rc.d/rc.0
if [ -x /sbin/genpowerd ]; then
  # See if this is a powerfail situation:
  if grep FAIL /etc/upsstatus 1> /dev/null 2> /dev/null ; then
    # Signal UPS to shut off the inverter:
    /sbin/genpowerd -k /dev/ttyS4 tripp-nt
    if [ ! $? = 0 ]; then
      echo
      echo "There was an error signaling the UPS."
      echo "Perhaps you need to edit /etc/rc.d/rc.6 to configure"
      echo "the serial line and UPS type."
      # Wasting 15 seconds of precious power:
      sleep 15
    fi
  fi
fi

/sbin/genpowerd が実行可能であれば、/etc/upsstatus を読み込み rc.0 の実行が、電源異常によるものであるかを確認します。電源異常によるものであれば、/sbin/genpowerd -k /dev/ttyS4 tripp-nt を実行し UPS に電源遮断を依頼します。UPS への依頼においてエラーが生じた場合はメッセージを表示します。

/etc/rc.d/rc.0
# Now halt (poweroff with APM kernels) or reboot.
if [ "$command" = "reboot" ]; then
  echo "Rebooting."
  reboot
else
  poweroff
fi

$command が reboot であれば、reboot を実行します。それ以外であれば、poweroff を実行します。

実際には、reboot と poweroff は halt へのシンボリックリンクです。halt は reboot として実行された場合と、poweroff として実行された場合に応じて動作を変えます。

poweroff として実行された halt は、オプション -p が指定されたものとして動作します。すなわち、システム停止後に電源を遮断します。但し、電源遮断には APM サポートが必要です。

最後に、以下のコマンドを実行した場合について説明します。

bash# shutdown -r now

オプション -r は、シャットダウン後にシステムを再起動することを指示します。

オプション -h との違いは、init プログラムに依頼するランレベルのみです。オプション -h を付けた場合は、ランレベル 6 へ変更するように依頼します。ランレベル 6 は再起動状態を表します。

依頼を受けた init プログラムは /etc/inittab に基づき /etc/rc.d/rc.6 を実行します。

そして、最後に reboot を実行します。

参考文献


前へ 起動プロセス入門 次へ