起動プロセス入門

更新年月日 - 2002 年 9 月 25 日

著者

Tomoaki Nishiguchi <admin@tomoakisoft.com>

環境

Slackware Linux 8.1

目次

  1. 目的
  2. init プログラム起動までの過程
  3. init プログラムの動作
  4. システム初期化処理
  5. モジュールの読み込み
  6. さまざまな設定
  7. agetty プログラムの動作
  8. login プログラムの動作
  9. bash の動作
  10. 起動プロセス概観
  11. シャットダウンプロセス

目的

この文章では、Slackware Linux の起動プロセスについて解説します。

起動プロセスについての知識を得ることは、一見地味な学習と思われがちです。しかし、起動プロセスを理解することは、あらゆるシステム管理の基礎であり、必要不可欠です。また、特に難解な部分もありません。現在起動しているプログラムが、いつどのようにして起動され、どういった場合に起動されるのかを知ることは実に興味深いことです。そして、起動プロセスの理解が、問題解決の大きな足掛かりになるということは疑いようのない事実なのです。


init プログラム起動までの過程

電源を入れた後、コンピュータは簡単な自己診断プログラムを実行します。異常がないことを確認すると BIOS 上での設定に基づき、マスタブートプログラムを実行します。ここでの設定とは マスタブートプログラムをどのデバイスから読み込むかを指定するものです。一般的にはフロッピーディスクから走査します。最もよく利用されているマスタブートプログラムには DOS 付属のものや、LILO、GNU GRUB などがあります。但し、DOS 付属のマスタブートプログラムを利用する場合には、セカンドブートプログラムとして LILO または GNU GRUB などを用意する必要があります。なぜなら、DOS 付属のブートプログラムは Linux カーネルを実行することができないからです。

Slackware Linux では LILO が標準のブートプログラムですので、LILO を例として説明します。マスタブートプログラムから実行された LILO または、マスタブートプログラムとして実行された LILO は次に Linux カーネルを実行します。Slackware Linux では /boot/vmlinuz が Linux カーネルです。

ブートプログラムはその役目を終え、制御は Linux カーネルに移ります。そして、Linux カーネルはハードウェアの自動認識を試みます。ほとんどのハードウェアはここで認識されることになります。

最後に Linux カーネルは init プログラムを実行します。Slackware Linux では /sbin/init が実行されます。

ここで少しカーネルソースを読んでみます。

/usr/src/linux/init/main.c
805 static int init(void * unused)
806 {
807         lock_kernel();
808         do_basic_setup();
809
810         prepare_namespace();
811
812         /*
813          * Ok, we have completed the initial bootup, and
814          * we're essentially up and running. Get rid of the
815          * initmem segments and start the user-mode stuff..
816          */
817         free_initmem();
818         unlock_kernel();
819
820         if (open("/dev/console", O_RDWR, 0) < 0)
821                 printk("Warning: unable to open an initial console.¥n");
822
823         (void) dup(0);
824         (void) dup(0);
825
826         /*
827          * We try each of these until one succeeds.
828          *
829          * The Bourne shell can be used instead of init if we are
830          * trying to recover a really broken machine.
831          */
832
833         if (execute_command)
834                 execve(execute_command,argv_init,envp_init);
835         execve("/sbin/init",argv_init,envp_init);
836         execve("/etc/init",argv_init,envp_init);
837         execve("/bin/init",argv_init,envp_init);
838         execve("/bin/sh",argv_init,envp_init);
839         panic("No init found.  Try passing init= option to kernel.");
840 }

835 行目で /sbin/init を実行しようとしているのが分かります。/sbin/init を実行することができなかった場合にのみ /etc/init の実行を試みます。以下その繰り返しです。但し、Slackware Linux で使われるいくつかのプログラムは /sbin/init 以外は認識しません。よって、init プログラムは /sbin/init とするべきです。

参考文献


init プログラムの動作

init プログラムは、設定ファイル inittab に基づいて動作します。また、init プログラムはランレベルという概念を用いています。これは、システムの状態を表します。

/etc/inittab
# These are the default runlevels in Slackware:
#   0 = halt
#   1 = single user mode
#   2 = unused (but configured the same as runlevel 3)
#   3 = multiuser mode (default Slackware runlevel)
#   4 = X11 with KDM/GDM/XDM (session managers)
#   5 = unused (but configured the same as runlevel 3)
#   6 = reboot

Slackware Linux デフォルトの inittab によると、ランレベル 0 は電源遮断状態、ランレベル 1 はシングルユーザモード、ランレベル 3 はマルチユーザモード、ランレベル 4 は X window 用のモード、ランレベル 6 は再起動状態と定義されています。ランレベル 2 と 5 は使われません。

/etc/inittab
# Default runlevel. (Do not set to 0 or 6)
id:3:initdefault:

ここでは、デフォルトのランレベルが定義されます。ランレベル 3、すなわちマルチユーザモードがデフォルトのランレベルとなります。

/etc/inittab
# System initialization (runs when system boots).
si:S:sysinit:/etc/rc.d/rc.S

システム起動時に /etc/rc.d/rc.S を実行します。/etc/rc.d/rc.S ではシステムの初期化処理を行います。

/etc/inittab
# Script to run when going single user (runlevel 1).
su:1S:wait:/etc/rc.d/rc.K

ランレベルが 1 またはシングルユーザモードへ移行した時 /etc/rc.d/rc.K を実行します。/etc/rc.d/rc.K ではすべてのデーモンを終了します。init は /etc/rc.d/rc.K の終了を待ちます。

/etc/inittab
# Script to run when going multi user.
rc:2345:wait:/etc/rc.d/rc.M

ランレベルが 2、3、4、5 のいずれかへ移行した時 /etc/rc.d/rc.M を実行します。/etc/rc.d/rc.M ではさまざまな設定を行います。init は /etc/rc.d/rc.M の終了を待ちます。

/etc/inittab
# What to do at the "Three Finger Salute".
ca::ctrlaltdel:/sbin/shutdown -t5 -r now

CTRL-ALT-DEL が押された時 /sbin/shutdown -t5 -r now を実行します。/sbin/shutdown -t5 -r now は 5 秒後にシステムを再起動します。

/etc/inittab
# Runlevel 0 halts the system.
l0:0:wait:/etc/rc.d/rc.0

ランレベルが 0 へ移行した時 /etc/rc.d/rc.0 を実行します。/etc/rc.d/rc.0 では終了処理を行います。init は /etc/rc.d/rc.0 の終了を待ちます。

/etc/inittab
# Runlevel 6 reboots the system.
l6:6:wait:/etc/rc.d/rc.6

ランレベルが 6 へ移行した時 /etc/rc.d/rc.6 を実行します。/etc/rc.d/rc.6 では終了処理を行います。init は /etc/rc.d/rc.6 の終了を待ちます。

/etc/inittab
# What to do when power fails.
pf::powerfail:/sbin/genpowerfail start

電源に異常が起きた時 /sbin/genpowerfail start を実行します。init はこのことを UPS 管理デーモンにより知らされます。init は /sbin/genpowerfail start の終了を待ちません。

/etc/inittab
# If power is back, cancel the running shutdown.
pg::powerokwait:/sbin/genpowerfail stop

電源異常状態から復帰した時 /sbin/genpowerfail stop を実行します。init は /sbin/genpowerfail stop の終了を待ちます。

/etc/inittab
# These are the standard console login getties in multiuser mode:
c1:1235:respawn:/sbin/agetty 38400 tty1 linux
c2:1235:respawn:/sbin/agetty 38400 tty2 linux
c3:1235:respawn:/sbin/agetty 38400 tty3 linux
c4:1235:respawn:/sbin/agetty 38400 tty4 linux
c5:1235:respawn:/sbin/agetty 38400 tty5 linux
c6:12345:respawn:/sbin/agetty 38400 tty6 linux

ランレベルが 1、2、3、5 のいずれかへ移行した時 agetty を 6 個起動します。ランレベルが 4 へ移行した時は agetty を 1 個だけ起動します。init は agetty の終了後、再び agetty を起動します。但し、ここでの agetty 終了とは、結果的にログインシェルの終了を意味します。

/etc/inittab
# Runlevel 4 used to be for an X window only system, until we discovered
# that it throws init into a loop that keeps your load avg at least 1 all
# the time. Thus, there is now one getty opened on tty6. Hopefully no one
# will notice. ;^)
# It might not be bad to have one text console anyway, in case something
# happens to X.
x1:4:wait:/etc/rc.d/rc.4

ランレベルが 4 へ移行した時 /etc/rc.d/rc.4 を実行します。init は /etc/rc.d/rc.4 の終了を待ちます。

マルチユーザモードを例に、実行されるプログラムを追うと次のようになります。

  1. /etc/rc.d/rc.S - システム初期化処理
  2. /etc/rc.d/rc.M - さまざまな設定
  3. /sbin/agetty 38400 tty1 linux - tty ポートを開きログインプロンプトを出力する
  4. /sbin/agetty 38400 tty2 linux
  5. /sbin/agetty 38400 tty3 linux
  6. /sbin/agetty 38400 tty4 linux
  7. /sbin/agetty 38400 tty5 linux
  8. /sbin/agetty 38400 tty6 linux

参考文献


システム初期化処理

システム初期化処理は /etc/rc.d/rc.S で行います。/etc/rc.d/rc.S は Bourne シェルスクリプトです。

/etc/rc.d/rc.S
PATH=/sbin:/usr/sbin:/bin:/usr/bin

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

/etc/rc.d/rc.S
# Start devfsd if necessary
if [ -r /dev/.devfsd ]; then
  if [ -x /sbin/devfsd ]; then
    echo "Starting devfs daemon:  /sbin/devfsd /dev"
    /sbin/devfsd /dev
  fi
fi

/dev/.devfsd が読み取り可能であり、/sbin/devfsd が実行可能であれば /sbin/devfsd /dev を実行します。

/etc/rc.d/rc.S
# enable swapping
/sbin/swapon -a

スワッピングを有効にします。

/etc/rc.d/rc.S
# Test to see if the root partition is read-only, like it ought to be.
READWRITE=no
if echo -n >> "Testing filesystem status"; then
  rm -f "Testing filesystem status"
  READWRITE=yes
fi

ルートパーティションの状態を調べます。読み取り専用の場合は READWRITE を no と設定します。読み書きが可能な場合は READWRITE を yes と設定します。

/etc/rc.d/rc.S
# See if a forced filesystem check was requested at shutdown:
if [ -r /etc/forcefsck ]; then
  FORCEFSCK="-f"
fi

/etc/forcefsck が読み込み可能であれば、FORCEFSCK を -f と設定します。

/etc/rc.d/rc.S
# Check the root filesystem:
if [ ! $READWRITE = yes ]; then
  if [ ! -r /etc/fastboot ]; then
    echo "Checking root filesystem:"
    /sbin/fsck $FORCEFSCK -C -a /
  fi
  # If there was a failure, drop into single-user mode.
  if [ $? -gt 1 ] ; then
    echo
    echo
    echo "***********************************************************"
    echo "*** An error occurred during the root filesystem check. ***"
    echo "*** You will now be given a chance to log into the      ***"
    echo "*** system in single-user mode to fix the problem.      ***"
    echo "***                                                     ***"
    echo "*** If you are using the ext2 filesystem, running       ***"
    echo "*** 'e2fsck -v -y <partition>' might help.              ***"
    echo "***********************************************************"
    echo
    echo "Once you exit the single-user shell, the system will reboot."
    echo
    PS1="(Repair filesystem) ¥#"; export PS1
    sulogin
    echo "Unmounting file systems."
    umount -a -r
    mount -n -o remount,ro /
    echo "Rebooting system."
    sleep 2
    reboot -f
  fi
  # Remount the root filesystem in read-write mode
  echo "Remounting root device with read-write enabled."
  /sbin/mount -w -v -n -o remount /
  if [ $? -gt 0 ] ; then
    echo
    echo "Attempt to remount root device as read-write failed!  This is going to"
    echo "cause serious problems."
    echo
    echo "If you're using the UMSDOS filesystem, you **MUST** mount the root partition"
    echo "read-write!  You can make sure the root filesystem is getting mounted "
    echo "read-write with the 'rw' flag to Loadlin:"
    echo
    echo "loadlin vmlinuz root=/dev/hda1 rw   (replace /dev/hda1 with your root device)"
    echo
    echo "Normal bootdisks can be made to mount a system read-write with the rdev command:"
    echo
    echo "rdev -R /dev/fd0 0"
    echo
    echo "You can also get into your system by using a boot disk with a command like this"
    echo "on the LILO prompt line:  (change the root partition name as needed)"
    echo
    echo "LILO: mount root=/dev/hda1 rw"
    echo
    echo "Please press ENTER to continue, then reboot and use one of the above methods to"
    echo -n "get into your machine and start looking for the problem. "
    read junk;
  fi
else
  echo "Testing filesystem status: read-write filesystem"
  if cat /etc/fstab | grep ' / ' | grep umsdos 1> /dev/null 2> /dev/null ; then
    ROOTTYPE="umsdos"
  fi
  if [ ! "$ROOTTYPE" = "umsdos" ]; then # no warn for UMSDOS
    echo
    echo "*** ERROR: Root partition has already been mounted read-write. Cannot check!"
    echo
    echo "For filesystem checking to work properly, your system must initially mount"
    echo "the root partition as read only. Please modify your kernel with 'rdev' so that"
    echo "it does this. If you're booting with LILO, add a line:"
    echo
    echo "   read-only"
    echo
    echo "to the Linux section in your /etc/lilo.conf and type 'lilo' to reinstall it."
    echo
    echo "If you boot from a kernel on a floppy disk, put it in the drive and type:"
    echo "   rdev -R /dev/fd0 1"
    echo
    echo "If you boot from a bootdisk, or with Loadlin, you can add the 'ro' flag."
    echo
    echo "This will fix the problem *AND* eliminate this annoying message. :^)"
    echo
    echo -n "Press ENTER to continue. "
    read junk;
  fi
fi # Done checking root filesystem

ルートファイルシステムが読み取り専用であり、/etc/fastboot が存在しなければ /sbin/fsck $FORCEFSCK -C -a / を実行しファイルシステムのチェックを行います。エラーが起きた場合はシングルユーザモードでログインします。シングルユーザモードからログアウトした後は、再起動します。エラーが起きなかった場合は、ルートファイルシステムを読み書き可能なモードで再マウントします。エラーが起きた場合は対処法を示し実行を続けます。

ルートファイルシステムが読み書き可能であれば、/etc/fstab を検査します。その結果、ルートファイルシステムが UMSDOS と分かれば ROOTTYPE を umsdos と設定します。UMSDOS ではない場合は、エラーメッセージと対処法を表示します。

/etc/rc.d/rc.S
# Any /etc/mtab that exists here is old, so we delete it to start over:
/bin/rm -f /etc/mtab*
# Remounting the / partition will initialize the new /etc/mtab:
/sbin/mount -w -o remount /

すでに古くなった /etc/mtab* を消去し、/sbin/mount -w -o remount / を実行して読み書き可能なモードで再マウントします。これにより、/etc/mtab が初期化されます。

/etc/rc.d/rc.S
# Initialize the Logical Volume Manager.
# This won't start unless /etc/lvmtab is found, which is created by /sbin/vgscan.
# Therefore, to use LVM you must run /sbin/vgscan yourself the first time.
if [ -r /etc/lvmtab ]; then
  # Mount /proc early (it's needed for vgscan):
  /sbin/mount -a -t proc
  # Scan for new volume groups:
  /sbin/vgscan
  if [ $? = 0 ]; then
    # Make volume groups available to the kernel:
    /sbin/vgchange -ay
  fi
fi

/etc/lvmtab が読み取り可能であれば、/sbin/mount -a -t proc を実行して /proc をマウントします。そして、/sbin/vgscan を実行しエラーが発生しなければ、/sbin/vgchange -ay を実行します。

/etc/rc.d/rc.S
# Check all the non-root filesystems:
if [ ! -r /etc/fastboot ]; then
  echo "Checking non-root filesystems:"
  /sbin/fsck $FORCEFSCK -C -R -A -a
fi

/etc/fastboot が読み込み可能でない場合、/sbin/fsck $FORCEFSCK -C -R -A -a を実行して、ルートファイルシステム以外をチェックします。

/etc/rc.d/rc.S
# mount non-root file systems in fstab (but not NFS or SMB
# because TCP/IP is not yet configured):
/sbin/mount -a -v -t nonfs,nosmbfs

/sbin/mount -a -v -t nonfs,nosmbfs を実行して、ルートファイルシステム以外をマウントします。但し、まだ TCP/IP の設定がされていないので、NFS と SMB ファイルシステムはマウントしません。

/etc/rc.d/rc.S
# Clean up some temporary files:
( cd /var/log/setup/tmp && rm -rf * )
/bin/rm -f /var/run/utmp /var/run/*pid /etc/nologin /var/run/lpd* ¥
  /var/run/ppp* /etc/dhcpc/dhcpcd-eth0.pid /etc/forcefsck /etc/fastboot

いくつかのテンポラリファイルを削除します。

/etc/rc.d/rc.S
# Create a fresh utmp file:
cat /dev/null > /var/run/utmp

新しい utmp ファイルを作成します。

/etc/rc.d/rc.S
if [ "$ROOTTYPE" = "umsdos" ]; then # we need to update any files added in DOS:
  echo "Synchronizing UMSDOS directory structure:"
  echo "  umssync -r99 -v- /"
  umssync -r99 -v- /
fi

ルートファイルシステムが UMSDOS であれば、umssync -r99 -v- / を実行します。

/etc/rc.d/rc.S
# Setup the /etc/motd to reflect the current kernel level:
# THIS WIPES ANY CHANGES YOU MAKE TO /ETC/MOTD WITH EACH BOOT.
# COMMENT THIS OUT IF YOU WANT TO MAKE A CUSTOM VERSION.
echo "`/bin/uname -sr`." > /etc/motd

/etc/motd を作成します。/etc/motd の内容はカーネルのバージョンを含んだものとなります。

/etc/rc.d/rc.S
# Configure ISA Plug-and-Play devices:
if [ -r /etc/isapnp.conf ]; then
  if [ -x /sbin/isapnp ]; then
    /sbin/isapnp /etc/isapnp.conf
  fi
fi

/etc/isapnp.conf が読み取り可能であり、/sbin/isapnp が実行可能であれば、/sbin/isapnp /etc/isapnp.conf を実行します。

/etc/rc.d/rc.S
# Set the system time from the hardware clock using hwclock --hctosys.
# 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 "Setting system time from the hardware clock (UTC)."
    /sbin/hwclock --utc --hctosys
  else
    echo "Setting system time from the hardware clock (localtime)."
    /sbin/hwclock --localtime --hctosys
  fi
fi

システムタイムを設定します。但し、SGI Visual Workstation であることを検出した場合は、何もしません。/sbin/hwclock が実行可能であれば、/etc/hardwareclock を検査します。UTC と記載されている場合は、/sbin/hwclock --utc --hctosys を実行します。UTC と記載されていなければ、/sbin/hwclock --localtime --hctosys を実行します。

/etc/rc.d/rc.S
# This loads any kernel modules that are needed.  These might be required to
# use your CD-ROM drive, bus mouse, ethernet card, or other optional hardware.
if [ -x /etc/rc.d/rc.modules ]; then
  . /etc/rc.d/rc.modules
fi

/etc/rc.d/rc.modules が実行可能であれば、/etc/rc.d/rc.modules を実行します。これは、Bourne シェルスクリプトです。いくつかのモジュールを読み込みます。

/etc/rc.d/rc.S
# Carry an entropy pool between reboots to improve randomness.
# Load and then save 512 bytes, which is the size of the entropy pool.
if [ -f /etc/random-seed ]; then
  echo "Using /etc/random-seed to initialize /dev/urandom."
  cat /etc/random-seed >/dev/urandom
fi
dd if=/dev/urandom of=/etc/random-seed count=1 bs=512 2> /dev/null

/etc/random-seed が普通のファイルであれば、cat /etc/random-seed >/dev/urandom を実行します。そして、いずれの場合でも dd if=/dev/urandom of=/etc/random-seed count=1 bs=512 2> /dev/null を実行します。これらは、より良い乱数を発生させるための準備です。

参考文献


モジュールの読み込み

モジュールの読み込みは /etc/rc.d/rc.modules で行います。/etc/rc.d/rc.modules は Bourne シェルスクリプトです。

/etc/rc.d/rc.modules
### Update module dependencies ###
# If /usr is mounted and we have 'find', we can try to take a shortcut:
RELEASE=`uname -r`
if [ -e /lib/modules/$RELEASE/modules.dep -a /lib/modules/$RELEASE/modules.dep -nt /etc/modules.conf ]; then
  NEWMODS="`/usr/bin/find /lib/modules/$RELEASE -type f -newer /lib/modules/$RELEASE/modules.dep`"
  # Only rebuild dependencies if new module(s) are found:
  if [ ! "" = "$NEWMODS" ]; then
    echo "New kernel modules have been found in /lib/modules/$RELEASE/:"
    echo "$NEWMODS"
    echo "Updating module dependencies for Linux $RELEASE:"
    /sbin/depmod -a
  else
    echo "Module dependencies up to date (no new kernel modules found)."
  fi
else # we don't have find, or there is no existing modules.dep, or it is out of date.
  echo "Updating module dependencies for Linux $RELEASE:"
  /sbin/depmod -A
fi

RELEASE に uname -r の出力結果を代入します。/lib/modules/$RELEASE/modules.dep が存在し、/lib/modules/$RELEASE/modules.dep が /etc/modules.conf よりも新しい場合、NEWMODS に /usr/bin/find /lib/modules/$RELEASE -type f -newer /lib/modules/$RELEASE/modules.dep の出力結果を代入します。これは、前回の depmod 実行以降に変更されたファイルを検出します。変更された、あるいは追加されたファイルを検出した場合 /sbin/depmod -a を実行し、新しい modules.dep を作成します。

/lib/modules/$RELEASE/modules.dep が存在しない場合は、/sbin/depmod -A を実行し modules.dep を作成します。また /etc/modules.conf が変更され、modules.dep が古い場合も /sbin/depmod -A を実行します。

コメント部分に find がない場合は /sbin/depmod -A を実行するとありますが、間違いです。find がない場合は正しく動作しません。find は大変便利なプログラムですので、インストールすることをお薦めします。find をインストールしない場合は、以下のように書き換える必要があります。

/etc/rc.d/rc.modules
### Update module dependencies ###
# If /usr is mounted and we have 'find', we can try to take a shortcut:
RELEASE=`uname -r`
if [ -e /lib/modules/$RELEASE/modules.dep -a /lib/modules/$RELEASE/modules.dep -nt /etc/modules.conf ]; then
  if [ -x /usr/bin/find ]; then
    NEWMODS="`/usr/bin/find /lib/modules/$RELEASE -type f -newer /lib/modules/$RELEASE/modules.dep`"
    # Only rebuild dependencies if new module(s) are found:
    if [ ! "" = "$NEWMODS" ]; then
      echo "New kernel modules have been found in /lib/modules/$RELEASE/:"
      echo "$NEWMODS"
      echo "Updating module dependencies for Linux $RELEASE:"
      /sbin/depmod -a
    else
      echo "Module dependencies up to date (no new kernel modules found)."
    fi
  else
    echo "Updating module dependencies for Linux $RELEASE:"
    /sbin/depmod -a
  fi
else # we don't have find, or there is no existing modules.dep, or it is out of date.
  echo "Updating module dependencies for Linux $RELEASE:"
  /sbin/depmod -A
fi

find を利用すると、必要な時にのみ /sbin/depmod -a を実行します。find がない場合は、毎回 /sbin/depmod -a を実行することになります。すなわち、find は起動時間を短縮するために利用されています。

/etc/rc.d/rc.modules
### Network device support ###
# Most of these drivers will probe automatically for the card if you don't
# specify an I/O address and IRQ.  But, the NE2000 driver needs at least the
# I/O.  For complete information, see the net-modules.txt file that comes
# with the Linux 2.2.x source code.  This file can also be found on the
# Slackware CD-ROM in the /docs/linux-2.2.x/ directory.
#
# First, if setup probing found a network card, there may be an 'rc.netdevice'
# file that we should run to load the network module:
if [ -x /etc/rc.d/rc.netdevice ]; then
  . /etc/rc.d/rc.netdevice
fi

/etc/rc.d/rc.netdevice が実行可能であれば、/etc/rc.d/rc.netdevice を実行します。これは、主にネットワークインタフェースカード用のモジュールを読み込みます。

/etc/rc.d/rc.modules
# *** THIS IS STILL LOADED BY DEFAULT ***
# SCSI emulation support.  This will provide SCSI host adapter emulation
# for IDE ATAPI devices, and will allow you to use a SCSI device driver
# instead of a native ATAPI driver.  This is useful if you have an ATAPI
# device for which no native driver has been written (for example, an ATAPI
# PD-CD or CD-RW drive); you can then use this emulation together with an
# appropriate SCSI device driver.  Note that this option does NOT allow you
# to attach SCSI devices to a box that doesn't have a SCSI host adapter
# installed.  Also, you'll need to exclude your CD-RW from being grabbed by
# the normal ATAPI driver by passing a flag to the kernel at boot time.
# If you're using LILO, add this:  append="hdc=ide-scsi"
# Replace "hdc" with the appropriate device name.
/sbin/modprobe ide-scsi

/sbin/modprobe ide-scsi を実行し、モジュール ide-scsi を読み込みます。

参考文献


さまざまな設定

さまざまな設定は /etc/rc.d/rc.M で行います。/etc/rc.d/rc.M は Bourne シェルスクリプトです。

/etc/rc.d/rc.M
# Screen blanks after 15 minutes idle time.
/bin/setterm -blank 15

/bin/setterm -blank 15 を実行します。これは、15 分間アイドル状態が続いた場合に画面をブランクにします。

/etc/rc.d/rc.M
# If there's no /etc/HOSTNAME, fall back on this default:
if [ ! -r /etc/HOSTNAME ]; then
  echo "darkstar.example.net" > /etc/HOSTNAME
fi

/etc/HOSTNAME が読み込み可能でない場合は、/etc/HOSTNAME を新規作成し darkstar.example.net と書き込みます。

/etc/rc.d/rc.M
# Set the hostname.
/bin/hostname `cat /etc/HOSTNAME | cut -f1 -d .`

ホスト名を設定します。ホスト名は /etc/HOSTNAME から読み込みます。

/etc/rc.d/rc.M
# Initialize PCMCIA devices:
#
# NOTE: This used to be started near the top of rc.S so that PCMCIA devices
# could be fsck'ed along with the other drives.  This had some unfortunate
# side effects, however, since root isn't yet read-write, and /var might not
# even be mounted the .pid files can't be correctly written in /var/run and
# the pcmcia system can't be correctly shut down.  If you want some PCMCIA
# partition to be mounted at boot (or when the card is inserted) then add
# the appropriate lines to /etc/pcmcia/scsi.opts.
#
if [ -x /etc/rc.d/rc.pcmcia ] ; then
  . /etc/rc.d/rc.pcmcia start
  # The cards might need a little extra time here to initialize.
  if [ -r /var/run/cardmgr.pid ]; then
    sleep 5
  fi
fi

/etc/rc.d/rc.pcmcia が実行可能であれば、/etc/rc.d/rc.pcmcia start を実行します。これは、PCMCIA デバイスの初期化を行います。次に /var/run/cardmgr.pid が読み込み可能であれば sleep 5 を実行します。これは 5 秒間待ちます。

/etc/rc.d/rc.M
# Initialize the network subsystem.
if [ -x /etc/rc.d/rc.inet1 ]; then
  . /etc/rc.d/rc.inet1
fi
if [ -x /etc/rc.d/rc.inet2 ]; then
  . /etc/rc.d/rc.inet2
else
  # Start the system logger.  Normally this is started by
  # rc.inet2 because /usr might be mounted via NFS.
  if [ -x /etc/rc.d/rc.syslog ]; then
    . /etc/rc.d/rc.syslog start
  fi
fi

/etc/rc.d/rc.inet1 が実行可能であれば、/etc/rc.d/rc.inet1 を実行します。これは、ネットワークの設定を行います。

/etc/rc.d/rc.inet2 が実行可能であれば、/etc/rc.d/rc.inet2 を実行します。これも、ネットワークの設定を行います。/etc/rc.d/rc.inet2 が実行可能でない場合は /etc/rc.d/rc.syslog を調べます。/etc/rc.d/rc.syslog が実行可能であれば、/etc/rc.d/rc.syslog start を実行します。これは、システムのログを記録するデーモンを起動します。

/etc/rc.d/rc.M
# Remove stale locks and junk files (must be done after mount -a!)
/bin/rm -f /var/lock/* /var/spool/uucp/LCK..* /tmp/.X*lock /tmp/core /core 1> /dev/null 2> /dev/null

古いロックファイルとジャンクファイルを削除します。

/etc/rc.d/rc.M
# Remove stale hunt sockets so the game can start.
if [ -r /tmp/hunt -o -r /tmp/hunt.stats ]; then
  echo "Removing your stale hunt sockets from /tmp."
  /bin/rm -f /tmp/hunt*
fi

/tmp/hunt あるいは /tmp/hunt.stats が読み込み可能であれば、/bin/rm -f /tmp/hunt* を実行し削除します。

/etc/rc.d/rc.M
# Ensure basic filesystem permissions sanity.
chmod 755 / 2> /dev/null
chmod 1777 /tmp /var/tmp

基本的なファイルシステムのパーミッションを正しく設定します。

/etc/rc.d/rc.M
# Update all the shared library links:
/sbin/ldconfig

/sbin/ldconfig を実行し、すべての共有ライブラリのリンクを更新します。

/etc/rc.d/rc.M
# Start the print spooling system.  This will usually be LPD or CUPS.
if [ -x /etc/rc.d/rc.cups ]; then
  # Start CUPS:
  /etc/rc.d/rc.cups start
elif [ -x /usr/sbin/lpd ]; then
  # Start LPD:
  echo "Starting the line printer daemon:  /usr/sbin/lpd"
  /usr/sbin/lpd
fi

/etc/rc.d/rc.cups が実行可能であれば、/etc/rc.d/rc.cups start を実行します。/etc/rc.d/rc.cups が実行可能でない場合は、/usr/sbin/lpd を調べます。/usr/sbin/lpd が実行可能であれば /usr/sbin/lpd を実行します。

/etc/rc.d/rc.M
# Turn on process accounting:
if [ -x /sbin/accton ]; then
  /sbin/accton /var/log/pacct
  chmod 640 /var/log/pacct
  echo "Process accounting turned on."
fi

/sbin/accton が実行可能であれば、/sbin/accton /var/log/pacct と chmod 640 /var/log/pacct を実行します。

/etc/rc.d/rc.M
# Start crond (Dillon's crond):
# If you want cron to actually log activity to /var/log/cron, then change
# -l10 to -l8 to increase the logging level.
if [ -x /usr/sbin/crond ]; then
  /usr/sbin/crond -l10 >>/var/log/cron 2>&1
fi

/usr/sbin/crond が実行可能であれば、/usr/sbin/crond -l10 >>/var/log/cron 2>&1 を実行します。これは cron デーモンを起動します。

/etc/rc.d/rc.M
# Start atd (manages jobs scheduled with 'at'):
if [ -x /usr/sbin/atd ]; then
  /usr/sbin/atd -b 15 -l 1
fi

/usr/sbin/atd が実行可能であれば、/usr/sbin/atd -b 15 -l 1 を実行します。これは at デーモンを起動します。

/etc/rc.d/rc.M
# Slackware-Mini-Quota-HOWTO:
# To really activate quotas, you'll need to add 'usrquota' to the appropriate
# partitions as listed in /etc/fstab.  Here's an example:
# /dev/hda2   /home   ext2   defaults,usrquota    1   1
# You'll then need to setup initial quota files at the top of the partitions
# to support quota, like this:
# touch /home/quota.user /home/quota.group
# chmod 600 /home/quota.user /home/quota.group
# Then, reboot to activate the system.
# To edit user quotas, use 'edquota'.  See 'man edquota'.  Also, the
# official Quota Mini-HOWTO has lots of useful information.  That can be found
# here:  /usr/doc/Linux-mini-HOWTOs/Quota

# Check quotas and then turn quota system on:
if fgrep quota /etc/fstab 1> /dev/null 2> /dev/null ; then
  if [ -x /sbin/quotacheck ]; then
    echo "Checking filesystem quotas:  /sbin/quotacheck -avugM"
    /sbin/quotacheck -avugM
  fi
  if [ -x /sbin/quotaon ]; then
    echo "Activating filesystem quotas:  /sbin/quotaon -avug"
    /sbin/quotaon -avug
  fi
fi

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

/etc/rc.d/rc.M
# Start the sendmail daemon:
if [ -x /etc/rc.d/rc.sendmail ]; then
  . /etc/rc.d/rc.sendmail start
fi

/etc/rc.d/rc.sendmail が実行可能であれば、/etc/rc.d/rc.sendmail start を実行します。これは、sendmail デーモンを起動します。

/etc/rc.d/rc.M
# Start the APM daemon if APM is enabled in the kernel:
if [ -x /usr/sbin/apmd ]; then
  if cat /proc/apm 1> /dev/null 2> /dev/null ; then
    echo "Starting APM daemon:  /usr/sbin/apmd"
    /usr/sbin/apmd
  fi
fi

/usr/sbin/apmd が実行可能であれば、cat /proc/apm 1> /dev/null 2> /dev/null を実行し、カーネルが APM に対応しているかどうかを調べます。対応している場合は、/usr/sbin/apmd を実行し、apm デーモンを起動します。

/etc/rc.d/rc.M
# Load a custom screen font if the user has an rc.font script.
if [ -x /etc/rc.d/rc.font ]; then
  . /etc/rc.d/rc.font
fi

/etc/rc.d/rc.font が実行可能であれば、/etc/rc.d/rc.font を実行します。これは、スクリーンフォントを読み込みます。

/etc/rc.d/rc.M
# Load a custom keymap if the user has an rc.keymap script.
if [ -x /etc/rc.d/rc.keymap ]; then
  . /etc/rc.d/rc.keymap
fi

/etc/rc.d/rc.keymap が実行可能であれば、/etc/rc.d/rc.keymap を実行します。これは、キーマップを読み込みます。

/etc/rc.d/rc.M
# Start Web server:
if [ -x /etc/rc.d/rc.httpd ]; then
  . /etc/rc.d/rc.httpd start
fi

/etc/rc.d/rc.httpd が実行可能であれば、/etc/rc.d/rc.httpd start を実行します。これは、Web サーバを起動します。

/etc/rc.d/rc.M
# Start Samba (a file/print server for Win95/NT machines).
# A copy of rc.samba can be found in the examples directory of the
# Samba docs.  Samba can also be started in /etc/inetd.conf.
if [ -x /etc/rc.d/rc.samba ]; then
  . /etc/rc.d/rc.samba start
fi

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

/etc/rc.d/rc.M
# Start the GPM mouse server:
if [ -x /etc/rc.d/rc.gpm ]; then
  . /etc/rc.d/rc.gpm start
fi

/etc/rc.d/rc.gpm が実行可能であれば、/etc/rc.d/rc.gpm start を実行します。これは GPM マウスサーバを起動します。

/etc/rc.d/rc.M
# 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 を実行します。これは、SystemV スタイルの初期化スクリプトとの互換性を保つために実行されるものです。

/etc/rc.d/rc.M
# Start the local setup procedure.
if [ -x /etc/rc.d/rc.local ]; then
  . /etc/rc.d/rc.local
fi

/etc/rc.d/rc.local が実行可能であれば、/etc/rc.d/rc.local を実行します。これは、ローカル用の初期化ファイルです。インストール直後には、何も書かれていません。

参考文献


agetty プログラムの動作

agetty は tty ポートを開き、ログイン名を求めます。

/etc/inittab
# These are the standard console login getties in multiuser mode:
c1:1235:respawn:/sbin/agetty 38400 tty1 linux
c2:1235:respawn:/sbin/agetty 38400 tty2 linux
c3:1235:respawn:/sbin/agetty 38400 tty3 linux
c4:1235:respawn:/sbin/agetty 38400 tty4 linux
c5:1235:respawn:/sbin/agetty 38400 tty5 linux
c6:12345:respawn:/sbin/agetty 38400 tty6 linux

/sbin/agetty 38400 tty1 linux を例として説明します。第一パラメータの 38400 は通信速度を指定します。単位は BPS です。次に、第二パラメータの tty1 は /dev/tty1 のことを示します。/dev/tty1 は第一番目の仮想コンソールです。そして、第三パラメータの linux は環境変数 TERM に代入されます。

起動された agetty は、まず /etc/issue の内容を表示します。

/etc/issue
Welcome to ¥s ¥r (¥l)

¥s、¥r、¥l はそれぞれ、OS の名前、OS のリリース番号、tty ライン名に置き換えられます。

/etc/issue の内容を表示した後、ログインプロンプトを表示し、ログイン名の入力を待ちます。ログインプロンプトはホスト名に login: が結合されたものです。

Welcome to Linux 2.4.18 (tty1)

darkstar login:

最後に、agetty は入力されたログイン名をパラメータとして /bin/login を実行します。但し、agetty は login を実行する際に fork-and-exec ではなく exec のみを用います。よって、プロセス ID は変わりません。

参考文献


login プログラムの動作

login はログイン名(ユーザ名)を引数として agetty により起動されます。設定ファイルは、/etc/login.def です。

/etc/passwd
root:x:0:0::/root:/bin/bash
nobody:x:99:99:nobody:/:
tomoaki:x:100:100:Tomoaki Nishiguchi:/home/tomoaki:/bin/bash

起動された login は、まず /etc/passwd を読み込みます。このファイルには、ユーザ名、パスワード、ユーザ ID、プライマリグループ ID、ユーザのフルネーム、ホームディレクトリ、ログインシェルが記載されています。パスワードフィールドが x となっている場合は、シャドウパスワードの利用を示します。

/etc/shadow
root::9804:0:::::
nobody:*:9797:0:::::
tomoaki::::::::

シャドウパスワードを利用している場合は、次に /etc/shadow を読み込みます。このファイルの第一フィールドにはユーザ名、第二フィールドには暗号化されたパスワードが記載されています。この例では、root と tomoaki にはパスワードが設定されていないことになります。また、パスワードフィールドの先頭文字が "*" あるいは "!" であれば、そのユーザのログインは許可されません。この例では、nobody のログインは許可されません。

パスワードが設定されている場合は、パスワードプロンプトを表示し、パスワードの入力を待ちます。

Password:

パスワード確認後、ログイン名が root であれば /etc/securetty を調べます。

/etc/securetty
# This file defines which devices root can log in on.

# These are the ttys on the physical console:
console
tty1
tty2
tty3
tty4
tty5
tty6

このファイルに列記されていないデバイスからの root ログインは許可されません。

問題がなければ、カレントディレクトリをホームディレクトリに変更し、環境変数の設定を行います。デフォルトで設定される環境変数は表 1 の通りです。

表 1 設定される環境変数
環境変数名値(ユーザ名 tomoaki)
HOME/home/tomoaki
SHELL/bin/bash
PATH/usr/local/bin:/bin:/usr/bin
USERtomoaki
LOGNAMEtomoaki
MAIL/var/spool/mail/tomoaki

環境変数設定後、ホームディレクトリ内のハッシュファイル .hushlogin の存在を確かめます。また、同時に環境変数 HUSHLOGIN の設定も行われます。ハッシュファイルが存在しなければ、/etc/motd の内容を表示します。ハッシュファイルが存在する場合は、ここでログインシェルを起動します。

Linux 2.4.18.

/var/log/lastlog を読み込み、最後にログインされた日時などを表示します。

Last login: Thu Sep 19 17:41:23 +0900 2002 on tty1.

メールボックスのパスを環境変数 MAIL から所得し、メールボックスの状態を表示します。

No mail.

そして、最後にログインシェルを起動します。

login はログインシェルを起動する際に、fork-and-exec ではなく exec のみを用います。

参考文献


bash の動作

bash は login により、ログインシェルとして起動されます。起動された bash は、/etc/profile、‾/.profile の順でそれぞれの内容を実行します。

/etc/profile
# Set the values for some environment variables:
export MINICOM="-c on"
export MANPATH=/usr/local/man:/usr/man:/usr/X11R6/man
export HOSTNAME="`cat /etc/HOSTNAME`"
export LESSOPEN="|lesspipe.sh %s"
export LESS="-M"

環境変数を設定します。

/etc/profile
# If the user doesn't have a .inputrc, use the one in /etc.
if [ ! -r "$HOME/.inputrc" ]; then
  export INPUTRC=/etc/inputrc
fi

ホームディレクトリ内の .inputrc が読み込み可能でない場合は、環境変数 INPUTRC を /etc/inputrc と設定します。

/etc/profile
# Set the default system $PATH:
PATH="/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/usr/games"

シェル変数 PATH を設定します。

/etc/profile
# For root users, ensure that /usr/local/sbin, /usr/sbin, and /sbin are in
# the $PATH.  Some means of connection don't add these by default (sshd comes
# to mind).
if [ "`id -u`" = "0" ]; then
  echo $PATH | grep /usr/local/sbin 1> /dev/null 2> /dev/null
  if [ ! $? = 0 ]; then
    PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH
  fi
fi

root であれば、シェル変数 PATH を調べます。/usr/local/sbin が含まれていなければ、/usr/local/sbin:/usr/sbin:/sbin を追加します。

/etc/profile
# I had problems using 'eval tset' instead of 'TERM=', but you might want to
# try it anyway. I think with the right /etc/termcap it would work great.
# eval `tset -sQ "$TERM"`
if [ "$TERM" = "" -o "$TERM" = "unknown" ]; then
 TERM=linux
fi

シェル変数 TERM が設定されていない、あるいは unknown であれば、TERM を linux と設定します。

/etc/profile
# Set default POSIX locale:
export LC_ALL=POSIX

環境変数 LC_ALL を POSIX と設定します。

/etc/profile
# Set ksh93 visual editing mode:
if [ "$SHELL" = "/bin/ksh" ]; then
  VISUAL=emacs
#  VISUAL=gmacs
#  VISUAL=vi
fi

シェル変数 SHELL が /bin/ksh であれば、シェル変数 VISUAL を emacs と設定します。

/etc/profile
# Set a default shell prompt:
#PS1='`hostname`:`pwd`# '
if [ "$SHELL" = "/bin/pdksh" ]; then
 PS1='! $ '
elif [ "$SHELL" = "/bin/ksh" ]; then
 PS1='! ${PWD/#$HOME/‾}$ '
elif [ "$SHELL" = "/bin/zsh" ]; then
 PS1='%n@%m:%‾%# '
elif [ "$SHELL" = "/bin/ash" ]; then
 PS1='$ '
else
 PS1='¥u@¥h:¥w¥$ '
fi

シェル変数 SHELL に応じて シェル変数 PS1 を設定します。

表 2 コマンドプロンプトの設定
シェル変数 SHELL の値シェル変数 PS1 の値
/bin/pdksh! $
/bin/ksh! ${PWD/#$HOME/‾}$
/bin/zsh%n@%m:%‾%#
/bin/ash$
上記以外¥u@¥h:¥w¥$

これは、コマンドプロンプトの設定です。

/etc/profile
PS2='> '

シェル変数 PS2 を > と設定します。これは、行継続プロンプトの設定です。

/etc/profile
export PATH DISPLAY LESS TERM PS1 PS2

シェル変数 PATH、DISPLAY、LESS、TERM、PS1、PS2 を環境変数とします。

/etc/profile
# Default umask.  A umask of 022 prevents new files from being created group
# and world writable.
umask 022

umask を 022 に設定します。

/etc/profile
# Set up the LS_COLORS and LS_OPTIONS environment variables for color ls:
if [ "$SHELL" = "/bin/zsh" ]; then
 eval `dircolors -z`
elif [ "$SHELL" = "/bin/ash" ]; then
 eval `dircolors -s`
else
 eval `dircolors -b`
fi

環境変数 SHELL が /bin/zsh であれば、dircolors -z の出力を実行します。同様に、環境変数 SHELL が /bin/ash であれば、dircolors -s の出力を実行します。環境変数 SHELL がそれら以外であれば、dircolors -b の出力を実行します。例として、dircolors -b の出力を解説します。

bash$ dircolors -b
LS_COLORS='no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;
01:or=40;31;01:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01
;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.bz
2=01;31:*.rpm=01;31:*.deb=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.jpg=01;35:*.gif
=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*
.mpg=01;37:*.avi=01;37:*.mov=01;37:';
export LS_COLORS;
LS_OPTIONS=' --color=auto -F -b -T 0';
export LS_OPTIONS;
alias ls='/bin/ls $LS_OPTIONS';
alias dir='/bin/ls $LS_OPTIONS --format=vertical';
alias vdir='/bin/ls $LS_OPTIONS --format=long';
alias d=dir;
alias v=vdir;

環境変数 LS_COLORS を設定します。これは、ls のカラー表示の設定です。次に、環境変数 LS_OPTIONS を --color=auto -F -b -T 0 と設定します。さらに、エイリアスの設定をします。

表 3 エイリアスの設定
エイリアス
ls/bin/ls $LS_OPTIONS
dir/bin/ls $LS_OPTIONS --format=vertical
vdir/bin/ls $LS_OPTIONS --format=long
ddir
vvdir

dircolors の設定ファイルは /etc/DIR_COLORS です。

/etc/profile
# Notify user of incoming mail.  This can be overridden in the user's
# local startup file (‾/.bash.login or whatever, depending on the shell)
if [ -x /usr/bin/biff ]; then
 biff y
fi

/usr/bin/biff が実行可能であれば、biff y を実行します。

/etc/profile
# Append any additional sh scripts found in /etc/profile.d/:
for file in /etc/profile.d/*.sh ; do
  if [ -x $file ]; then
    . $file
  fi
done

/etc/profile.d/ 内にある拡張子 sh のファイルをすべて調べます。実行可能であれば、それを実行します。

/etc/profile
# For non-root users, add the current directory to the search path:
if [ ! "`id -u`" = "0" ]; then
 PATH="$PATH:."
fi

root ユーザでない場合は、シェル変数 PATH に . を追加します。

そして、bash はコマンドプロンプトを表示します。

tomoaki@darkstar:‾$ _

参考文献


起動プロセス概観

起動プロセスの説明が一通り終了したところで、概観を図によって示します。

図 1 起動プロセス概観
図 1 起動プロセス概観

図 1 は、シェルスクリプトに重点をおいています。よって、骨組みに過ぎません。しかし、各スクリプトが実行するプログラムについては、すでに述べてきたように、容易に解読することが可能です。この見通しの良さは Slackware Linux の特徴です。


シャットダウンプロセス

起動プロセスをより深く知るためには、シャットダウンプロセスの理解が必要不可欠です。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 を実行します。

参考文献


Copyright (C) 2002 Tomoaki Nishiguchi <admin@tomoakisoft.com>