Linuxはどのように起動しますか

更新:記事とスクリプトは2013年3月に更新されました(5年が経過し、古いスクリプトは現在のものと大差ありませんが、現在のコードを調査する方が良いです。また、システムブートロジックは長年にわたって少し変更されました。 devtmpfsのように、 /var/run



/run



などに移動しました。



Linuxをマスターしたとき、システムのブート時に何が起こるかに非常に興味がありました。 ブートプロセスを理解しようとすると、ブートスクリプト( /etc/inittab, /etc/rc*, /etc/init.d/*, ...



/etc/sysconfig/*, /etc/cond.f/*, ...



/etc/inittab, /etc/rc*, /etc/init.d/*, ...



)とその構成( /etc/sysconfig/*, /etc/cond.f/*, ...



)。 これらのスクリプトの深刻なサイズと複雑さに注目する価値があります-それらを理解するのに多くの時間がかかりました。 しかし当時は、ダウンロードは複雑なプロセスであり、ブートスクリプトのサイズと複雑さは正当であると私は心から信じていました。



RedHatがついに私を獲得した(2001年)とき、 LFSベースのディストリビューションを構築することにしました。 私のディストリビューションでは、ブートスクリプトを自分で開発する必要があり、その後、真実が明らかになりました。ブートプロセスに複雑なものはありません。



私のディストリビューション(PoWeR Linux)で2.5年間働いた後、Gentooに移行しました(質の高いサポートを提供するのに十分な時間がなかっただけです)。 Gentooブートスクリプトを学んだ後、私はぞっとしました! それらのサイズと複雑さは、古いRedHatよりもさらに大きかったです。 詳細な調査の後、理由が明らかになりました。LiveCDと通常のシステムの両方に同じブートスクリプトのセットが使用されました。 そこで、Gentooに切り替えたときに、PoWeR Linuxからブートスクリプトを使用し、標準のGentooスクリプトを使用しないことにしました(つまり、GentooのPortageのみを使用します)。 それから、さらに4年間、これらのスクリプトは自宅のワークステーションと多数のリモートサーバーで機能していました。



特徴



スクリプトのサイズ(すべて合わせて)は308行、8 KBです。

 $ wc 1 3 lib.sh 201 769 5855 1 78 272 1726 3 29 118 771 lib.sh 308 1159 8352 
      
      





短所:

  1. すべて1つのファイルで -アプリケーションを更新するとき、このアプリケーションの初期化コードを自動的に更新することはほとんど不可能です。 たとえば、ALSAが更新されると、パッケージは/etc/init.d/alsasound, /etc/conf.d/alsasound, /etc/modules.d/alsa



    ファイルを単純に置き換える場合があります。 そして私の場合、管理者はペンで/etc/runit/1



    を編集する必要があります。
  2. 世界のすべてをサポートするものはありません。 たとえば、私はRAIDとLVMを使用していません。したがって、コマンドを追加して自分で初期化する必要があります。
  3. これらのスクリプトを個別にサポートする必要があります。 Gentooを更新するとき、私は通常(未使用の) /etc/init.d/*



    スクリプトの変更を調べ、何か重要な変更があればスクリプトを更新します。 しかし、実際には、このような変更の必要性は約2年ごとに発生します。


長所:

  1. すべて1つの小さなファイルで -必要なものを設定するためのスクリプトとその設定を探す必要はありません。 システムのすべての基本設定をすばやく簡単に確認できます。
  2. 私と私の友人が11.5 年間自宅のコンピューターとサーバーで必要としていたすべてのサポートがあります。
  3. Linux初期化プロセスの調査に最適です。 実際の基本的なLinuxコマンドを使用します。これは、すべてのディストリビューションで同じであり、ディストリビューション固有のスクリプトや構成ではありません。
  4. システムの読み込みを高速化します。 私のホームマシンは、 11秒でシングルユーザーモード(getty、syslog、klog、acpid、dnscache、tinydns、gpmを備えた6つのコンソール)でロードされます。 initngスタイルで並列ロードを試しました-スクリプトの複雑さと不要なプロセスの生成のため、効果はかなりマイナスです。 Initngは、多くの不要なアクションを実行する従来の肥大化したスクリプトの読み込みを高速化するのに適しています。私の場合、高速化するものは何もありません。 :)


サイズが小さいにもかかわらず、これらのスクリプトはシステムを確実かつ迅速にロードするだけでなく、管理者の生活を楽にするいくつかの機能もサポートしています。





起動時に表示されるメッセージの例



+ UDEV

+モジュール

+ SYSCTL

+ MTAB

-マウント



++スワップオン-a

++ false

終了コード:1

++ mount -at nocoda、nonfs、noproc、noncpfs、nosmbfs、noshm

... 5秒以内に任意のキーを押してシェルを開きます...

+ CLEANTMP

+ランダムシード

+ HWCLOCK

+センサー

+ロードキー

+サウンド

+ HOST_NAME

+ ENVUPDATE

+ネットワーク

+ RUNIT

+ DMESG







単位



SysVinitの代わりに、Runitを使用して起動します。 Runitは/etc/inittab



サポートしていません;代わりに、単純なスキームを使用します:

  1. ロードすると、スクリプト/etc/runit/1



    ます。 彼の仕事は、システムを完全に初期化することです。
  2. スクリプト/etc/runit/1



    が完了すると、スクリプト/etc/runit/1



    /etc/runit/2



    が起動され、必要なすべてのサービス(syslog、getty、ssh、apacheなど)が実行されます。
  3. ユーザーがシステムを停止/再起動すると、スクリプト/etc/runit/3



    これにより、システムをシャットダウンする準備ができます(すべてのプロセスを完了し、ディスクをマウント解除するなど)。


必要に応じて、同じスタイルで動作するようにSysVinitを構成できます。



SysVinitから/ etc / runit / {1,2,3}を実行:/ etc / inittab



id:3:initdefault:

rc :: bootwait:/ etc / runit / 1

l0:0:待機:/ bin / sh -c '/ etc / runit / 3; exec / sbin / halt '

l3:3:once:/ etc / runit / 2

l6:6:待機:/ bin / sh -c '/ etc / runit / 3; exec / sbin / reboot '

ca:12345:ctrlaltdel:/ sbin / shutdown -r now





サービス



すべてのサービス(getty、syslog、mysqlなど)を開始するには、同じrunitを使用します(実際には、わずかに改善されたdaemontoolsのバージョンです)。 ただし、これは別の大きなトピックなので、この記事ではサービスを起動するためのスクリプトはなく、ここではシステムの初期化/シャットダウンのみを行うことを明確にします。



ソースコード



ヘルパー関数:/etc/runit/lib.sh



 #!/bin/bash startlog() { exec 3>&1 4>&2 1> >(tee $1) 2>&1; } stoplog() { exec 1>&3- 2>&4-; } wanna() { echo -e "\a... press any key in $2 seconds to $1 ..." read -t $2 -n 1 -s </dev/console } emergency() { if wanna "open shell" 5; then bash --norc </dev/console &>/dev/console if [[ "$0" == "/etc/runit/1" ]] && wanna "reboot now" 3; then exit 100 fi fi } trace() { trap 'ERR=$?' ERR; set -Ex; $1 2>&1; set +Ex; trap ERR; } 2>&- try() { local output=$( trace $1 ) if [[ "$output" =~ "ERR=" ]]; then echo -e "\e[1m\e[31m - \e[37m$1\e[0m" echo "$output" | sed $'s/.*ERR=\(.*\)/\a\033[36mEXIT CODE: \\1\033[0m/g' emergency else echo -e "\e[1m\e[32m + \e[37m$1\e[0m" fi }
      
      







スタートアップ:/ etc / runit / 1



 #!/bin/bash CONSOLE() { dmesg -n 1 } INIT() { mount -n -t proc -o "noexec,nosuid,nodev" none /proc mount -n -t sysfs -o "noexec,nosuid,nodev" none /sys mount -n -t tmpfs -o "mode=0755,nosuid,nodev" none /run mkdir /run/lock chmod 0775 /run/lock chown root:uucp /run/lock if grep -qs devtmpfs /proc/mounts; then mount -n -t devtmpfs -o "remount,exec,nosuid,mode=0755,size=10M" none /dev elif grep -qs devtmpfs /proc/filesystems; then mount -n -t devtmpfs -o "exec,nosuid,mode=0755,size=10M" none /dev else mount -n -t tmpfs none /dev busybox mdev -s fi # needed to run startlog (in /etc/runit/lib.sh) before UDEV ln -snf /proc/self/fd /dev/fd # extra mountpoints in /dev mkdir -p /dev/pts mount -n -t devpts -o "noexec,nosuid,gid=5,mode=0620" none /dev/pts mkdir -p /dev/shm mount -n -t tmpfs -o "noexec,nosuid,nodev" none /dev/shm } UDEV() { echo "" >/proc/sys/kernel/hotplug udevd --daemon udevadm trigger --type=subsystems --action=add udevadm trigger --type=devices --action=add udevadm settle --timeout=30 } HWCLOCK() { hwclock --hctosys --localtime && touch /run/init.hwclock } MODULES() { true # bash doesn't allow empty functions # modprobe -q nvidia NVreg_DeviceFileMode=432 NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=27 NVreg_ModifyDeviceFiles=1 # modprobe -q -a vmmon vmci vsock vmblock vmnet # modprobe -q -a vboxdrv vboxnetflt vboxnetadp } FSCK() { fsck -A -p -C0 -T -t noafs,nocifs,nocoda,nodavfs,nofuse,nofuse.sshfs,nogfs,noglusterfs,nolustre,noncpfs,nonfs,nonfs4,noocfs2,noshfs,nosmbfs,noopts=_netdev } REMOUNT() { mount -n -o remount,rw / grep -v ^rootfs /proc/mounts > /etc/mtab for i in $(cut -d ' ' -f 2 /etc/mtab | grep -vx /); do mount -o remount "$i" done } LOCALMOUNT() { mount -at noproc,noafs,nocifs,nocoda,nodavfs,nofuse,nofuse.sshfs,nogfs,noglusterfs,nolustre,noncpfs,nonfs,nonfs4,noocfs2,noshfs,nosmbfs -O no_netdev swapon -a } SYSCTL() { sysctl -p /etc/sysctl.conf } MIGRATERUN() { rm -rf /var/lock ln -s /run/lock /var/lock rm -rf /var/run ln -s /run /var/run } UTMPWTMP() { > /var/run/utmp chgrp utmp /var/run/utmp chmod 0664 /var/run/utmp [ -e /var/log/wtmp ] || cp -a /var/run/utmp /var/log/wtmp } CLEANTMP() { rm -f /tmp/.X*-lock /tmp/esrv* /tmp/kio* /tmp/jpsock.* /tmp/.fam* rm -rf /tmp/.esd* /tmp/orbit-* /tmp/ssh-* /tmp/ksocket-* /tmp/.*-unix mkdir -p /tmp/.{ICE,X11}-unix chmod 1777 /tmp/.{ICE,X11}-unix } RANDOMSEED() { mkdir -p /var/lib/misc [ -f /var/lib/misc/random-seed ] && cat /var/lib/misc/random-seed >/dev/urandom rm -f /var/lib/misc/random-seed local psz=$(( $(sysctl -n kernel.random.poolsize 2>/dev/null || echo 4096) / 4096 )) (umask 077; dd if=/dev/urandom of=/var/lib/misc/random-seed count=$psz 2>/dev/null) } SENSORS() { sensors -s } LOADKEYS() { # Commands for TTY initialization like 'setfont' and 'echo -ne "\033(K"' # shouldn't be executed in /etc/runit/1 because: # - which TTYs should be initialized may depend on current runlevel # - if TTY state become broken (for ex. after 'cat /dev/urandom'), # then after logout and login TTY state should be reinitialized # these commands should be executed before each getty invocation instead. kbd_mode -u loadkeys koi2 # -q windowkeys # loadkeys -q -u ru4 dumpkeys -c koi8-r | loadkeys --unicode } SOUND() { alsactl -f /etc/asound.state restore && touch /run/init.alsa } HOST_NAME() { # Here you should set only "host" part of your fqdn. # Add this line to /etc/hosts to configure FQDN: # YOUR.IP.ADDR.ESS YOUR_HOSTNAME.DOMAIN.TLD YOUR_HOSTNAME hostname YOUR_HOSTNAME } NETWORK() { ip link set lo up iptables-restore </etc/iptables #ip link set eth0 up #ip addr add 192.168.1.2/24 dev eth0 #ip route add default via 192.168.1.1 dev eth0 } RUNIT() { # Set default action (shutdown or not) if Ctrl+Alt+Del pressed, # but /etc/runit/ctrlaltdel don't setup /etc/runit/stopit. touch /etc/runit/stopit chmod 100 /etc/runit/stopit # Set default action on shutdown (halt or reboot) if: # - /etc/runit/1 crash or exit 100 # - /etc/runit/2 exit non 111 # - Ctrl+Alt+Del pressed, but /etc/runit/ctrlaltdel don't setup /etc/runit/reboot touch /etc/runit/reboot chmod 100 /etc/runit/reboot # Set runlevel to: # - single if kernel has param: S # - RUNLEVELNAME if kernel has param: runlevel=RUNLEVELNAME # - default if kernel has no params or unable to set requested runlevel grep -q '\(^\| \)S\( \|$\)' /proc/cmdline && runlevel='single' runsvchdir ${runlevel:-default} || runsvchdir default } SEND_MAIL() { echo -e "To: root\nSubject: reboot at $(date)" | sendmail -t } DMESG() { # Create an 'after-boot' dmesg log dmesg > /var/log/dmesg chmod 640 /var/log/dmesg } PATH=/sbin:/usr/sbin:/bin:/usr/bin trap ':' INT QUIT TSTP . /etc/runit/lib.sh try CONSOLE try INIT startlog /run/boot.log try UDEV try HWCLOCK #try MODULES # Enable & configure this if you have modules support in kernel FSCK try REMOUNT try LOCALMOUNT try SYSCTL try MIGRATERUN try UTMPWTMP try CLEANTMP try RANDOMSEED #try SENSORS # Enable this if you have configured lm_sensors #try LOADKEYS # Enable & configure this for non-english keyboard layout #try SOUND # Enable this if you have sound card (also in /etc/runit/3!) try HOST_NAME # Do not forget to configure this try NETWORK # Do not forget to configure this try RUNIT #try SEND_MAIL # Enable this if you wanna receive notification email on reboot try DMESG stoplog mv /run/boot.log /var/log/boot # Select next stage (exit 0 for stage 2, exit 100 for stage 3): exit 0
      
      







シャットダウン:/ etc / runit / 3



 #!/bin/bash CONSOLE() { chvt 1 # Required in case getty was last process in this console and it leave # console in broken state (\n work as <LF> without <CR>). { stty sane ; echo ; } >/dev/console } TERM() { # Give a chance for all processes for clean exit. # This also will kill all 'runsvdir' and signal all 'runsv' to exit. killall5 -15 || [ $? -eq 2 ] } HWCLOCK() { test -f /run/init.hwclock && hwclock --systohc --localtime --noadjfile } SERVICES() { sv force-stop /var/service/* &>/dev/null || : } SOUND() { test -f /run/init.alsa && alsactl -f /etc/asound.state store } RANDOMSEED() { local psz=$(( $(sysctl -n kernel.random.poolsize 2>/dev/null || echo 4096) / 4096 )) (umask 077; dd if=/dev/urandom of=/var/lib/misc/random-seed count=$psz 2>/dev/null) } NETWORK() { ip link set group default down } WTMP() { halt -w } KILL() { # Goodbye to everybody... killall5 -9 || [ $? -eq 2 ] } UMOUNT() { sync; sync # Unmounting loopback devices first: for d in $(grep '^/dev/loop' /proc/mounts | cut -d ' ' -f 2 | tac); do eval "umount -d -r -f $'$d'" done # Unmounting all real filesystems except root: for d in $(egrep -v '^\S+ (/|/dev|/dev/.*|/proc|/proc/.*|/run|/sys|/sys/.*) ' /proc/mounts | cut -d ' ' -f 2 | tac); do eval "umount -r -f $'$d'" done # Switching off swap umount -a -t tmpfs 2>/dev/null || : swapoff -a } PATH=/sbin:/usr/sbin:/bin:/usr/bin trap ':' INT QUIT TSTP . /etc/runit/lib.sh try CONSOLE startlog /var/log/shutdown try TERM try HWCLOCK try SERVICES #try SOUND # Enable this if you have sound card try RANDOMSEED try NETWORK try WTMP try KILL try UMOUNT stoplog
      
      






All Articles