- linux運行層級
linux啟動之後會在一個層級運行,下面列出了這些運行層級:
0 系統停止
1 單使用者系統,不需要登陸
2 多使用者系統但不支援NFS,命令列模式登陸
3 完整多使用者模式,命令列模式登陸
4 未用
5 X11圖形模式,圖形模式登陸
6 重新啟動系統
這些可以在/etc/initab檔案中可以看到0-6級的注釋,程式碼片段如下:
# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
1.層級 0
系統停止。注意不要把該層級設定為預設模式,否則系統每次啟動以後就會自動停止,無法進入。
這個運行層級主要用於關閉任務,在 rc0.d 目錄下的各個串連命令都是此層級的命令。在關閉時,這些命令逐個執行。它們將殺掉所有進程、關閉虛擬記憶體和分頁檔、卸載檔案系統和交換分區。
關機操作在 DOS 下和 Linux 下截然不同。在 DOS 提示符下,可以很放心地直接關閉電源。但是,在 Linux 下不能這麼做。Linux 的檔案系統在啟動時被裝入,在關閉時要被卸載。這種差別正是 Linux 強大功能的前提。
在 Linux 下,要通過輸入命令 shutdown 加上參數來關閉、重啟電腦或者通過按下熱鍵“Ctrl”+“Alt”+“Del”來重新啟動。
2.層級 1
單一使用者模式。該模式只能許可一個使用者從本機電腦上登入 rc1.d 目錄下的所有檔案與此運行層級相連。此運行層級一般用於系統管理與維護,如:給 Linux 系統升級,安裝新軟體等等。
在此模式下,只能由管理員進入而其他使用者無法登入。因為在啟動時,檔案系統被載入但是網路卻沒有被載入,無法通過網路登入。
3.層級 2
多使用者模式。使用者可以通過網路進行登入。在不支援網路的情況下該模式和模式 3 是相的,rc2.d 目錄下所有檔案與此層級相連。
4.層級 3
完全多使用者模式。這是預設的運行模式,在此模式下所有網路服務程式一起運行。rc3.d錄下的檔案與此層級相連。
5.層級 4
未使用模式,rc4.d 目錄與此層級相連。這一層級是使用者自訂的運行層級,使用者可以根需要自己定義。如果想運行此層級的話,必須在 rc3.d 目錄下放入串連檔案,就像其他 rc*.d目錄下的檔案,並指明是啟動還是終止進程。
6.層級 5
在 Linux 下運行 X Window 就是使用這一層級。在此層級下除了網際網路的網域名稱伺服器的named 與層級 3 不同,其餘的都相同。
7.層級 6
這是個重新啟動系統的運行層級。rc6.d 目錄與此層級相連。既然是重新啟動也就是關閉當前系統,但不關閉電源,所以此目錄下的串連與層級為 0 的在 rc0.d 下的串連基本相同。不同之處在於,雖然它們都執行 halt(關閉)命令,但是給 halt 傳遞的參數不一樣,因而層級 6 能夠重新啟動系統。
- inittab檔案解釋
inittab檔案的格式:
label:runlevel:action:process
label:
1~4字元的標籤,可以是任一字元構成的字串,表示輸入的值。一些系統label為2個字元。某些特定的標籤是常用的,在Red Hat Linux中使用的標籤是:
id 用來定義預設的init啟動並執行層級
si 是系統初始化的進程
ln 其中的n從1~6,指明該進程可以使用的runlevel的層級
ud 是升級進程
ca 指明當按下Ctrl+Alt+Del是啟動並執行進程
pf 指當UPS表明斷電時啟動並執行進程
pr 是在系統真正關閉之前,UPS發出電源恢複的訊號時需要啟動並執行進程
x 是將系統轉入X終端時需要啟動並執行進程
runlevel:
定義該記錄項被調用時的運行層級,可以由一個或多個運行層級構成,也可以是空,空則代表運行層級0~6.
當請求init改變運行層級時,那些rstate欄位中不包括新運行層級的進程將收到SIGTERM警告訊號,並且最後被殺死;只有a、b、c啟動的命令外(a、b、c不是真正的運行層級) ????action:
定義了該進程應該運行在何種狀態下,即如何處理process欄位指定的進程.
代碼:
boot 只有在系統啟動時,init才處理這樣的記錄項,啟動相應進程,忽略runlevel,並不等待處理結束就去處理下一個記錄項。當這樣的進程終止時,系統也不重啟它。
bootwait 系統啟動後,當第一次從單一使用者模式進入多使用者模式時處理這樣的記錄項,init啟動這樣的進程,並且等待它的處理結束,然後再進行下一個記錄項的處理,當這樣的進程終止時,系統也不重啟它。
ctrlaltdel 當Ctrl+Alt+Del三個鍵同步選取時運行,把SIGINT訊號發送給init。忽略 runlevel
initdefault 指定一個預設的運行層級,只有當init一開始被調用時才掃描這一項,如果runlevel
欄位指定了多個運行層級,其中最大的數字是預設的運行層級,如果runlevel
欄位是空的,init認為欄位是0123456,於是進入層級6,這樣便陷入了一個迴圈,如果inittab檔案中沒有包含initdefault的記錄項,則在系統啟動時請求使用者為它指定一個初始運行層級
kbrequest 當init從鍵盤中收到訊號時運行。這裡要求鍵盤組合符合KeyBoardSigral(參見/usr/share/doc/kbd-*關於鍵盤組合的文檔)
off 啟動process欄位指定的進程如果指定的進程正在運行,init就給它發SIGTERM警告訊號,在向它發出訊號SIGKILL強制其結束之前等待5秒,如果這樣的進程不存在,則忽略這一項。
once不等待處理結束就去處理下一記錄項。當這樣的進程終止時,也不再重新啟動它,在進入新的運行層級時,如果這樣的進程仍在運行,init也不重新啟動它。
ondemand 功能同respawn 當系統指定特定的運行層級A、B、C時運行
powerfail 當init收到SIGPWR(斷電)訊號時運行
powerokwait 當收到SIGPWD訊號且/etc/檔案中的電源狀態包含OK時運行
powerwait 當收到SIGPWD訊號,並且init等待進程結束時運行
respawn 不管何時process中止,init都重新啟動進程,並且init不等到啟動結束而繼續掃描inittab中的後續process。如果process已經存在,就什麼也不做。
sysinit 在運行boot或bootwait進程之前運行,指定的進程在存取控制台之前執行,這樣的記錄項僅用於對某些裝置的初始化,目的是為了使init在這樣的裝置上向使用者提問有關運行層級的問題,init需要等待進程運行結束後才繼續。
wait 啟動process欄位指定的進程,並等到處理結束才去處理inittab中的下一記錄項。
process欄位包含init執行的進程,該進程採用的格式與在命令列下運行該進程的格式一樣,因此process欄位都以該進程的名字開頭,緊跟著是運行時,緊跟著是運行時要傳遞給該進程的參數。比如/sbin/shutdown -t3 -r now,該進程在按下Ctrl+Alt+Del時執行,在命令列下也可以直接輸入來重新啟動系統。
Process欄位中進程可以是任意的守候進程、可執行指令碼或程式。
另外:在任何時候,可以在檔案inittab中添加新的記錄項,層級Q/q不改變當前的運行層級,重新檢查inittab檔案,可以通過命令init Q或init q使init進程立即重新讀取並處理檔案inittab.
特殊目的的記錄
仔細學習例子檔案,學習應用其中關於inittab的文法格式。該檔案的大多數內容都可以忽略,因為超過一半的內容都是注釋,剩餘的一些檔案內容主要是用來實現某些特殊的功能:
id 的值表明預設的runlevel是3。
ud 的值可以喚醒/sbin/update進程,該進程為保持磁碟的完整性,將在對磁碟進行I/O操作之前清空整個I/O緩衝區。
pf、pr和ca的值只被特定的中斷所調用。
如果系統是專用的X終端,則只需x的輸入值。
getty進程來提供虛擬終端裝置的服務,例如:
3:2345:respawn:/sbin/mingetty tty3
標籤欄位的值是3,3是裝置tty3的數字尾碼,tty3與相應的進程相關聯,該getty進程可以啟動的runlevel是2、3、4和5,當該進程終止時,init馬上就重新啟動它。啟動進程的路徑名是/sbin/mingetty,該進程是實現虛擬終端支援的最小版本的getty,為tty3提供啟動虛擬設備的進程。
si::sysinit:/etc/rc.d/rc.sysinit
該值告訴init程式運行/etc/rc.d/rc.sysinit指令檔來初始化系統,該指令檔與所有啟動的指令碼類似,它只是一個包含Linux的 shell命令的可執行檔,注意輸入的字串必須包括該指令碼的完整路徑。不同版本的Linux存放該指令碼的位置也不相同,但不用刻意去記憶這些位置,只需查看/etc/inittab檔案即可,該檔案中包含啟動指令檔的確切位置。
redhat 9 預設initab檔案內容:
default runlevel
0 - halt (do not set initdefault to this)
1 - single user mode
2 - multiuser, without NFS (the same as 3, if you do not have a neworking)
3 - full multiuser mode
4 - unused
5 - X11
6 - reboot halt (do not set initdefault to this)
id:5:initdefault:
//預設init進程被調用時的運行層級為5(不能設為0和6,這樣系統將不能啟動)
si::sysinit:/etc/rc.d/rc.sysinit
//si是系統初始化進程,init程式運行/etc/rc.d/rc.sysinit指令檔來初始化系統,init等待指令碼運行結束才繼續運行下個進程。
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
//對相應運行層級,運行指令碼/etc/rc.d/rc,並傳入相應運行級參數0~6
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
//按下ctrl+alt+del時執行shutdown -t3 -r now
pf::powerfail:/sbin/shutdown -f -h +2
//當UPS電源提示斷電的時候,他還將提供幾分鐘時間供電,這時系統執行shutdown -f -h +2 (-f 表示重啟的時候跳過檔案系統的檢查)
pr:12345:powerwait:/shutdown -c
//表示供電恢複時取消正在執行的shutdown命令。
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
//2345運行級,運行對應的終端程式
x:5:respawn:/etc/X11/prefdm -nodaemon
//如果是x終端模式要啟動並執行程式
- linux自動啟動指令碼
linux啟動之後會運行一個init程式,首先讀取inittab設定檔,決定系統的運行模式,在讀取inittab的過程中,執行rc0.d~rc6.d目錄下的運行層級指令碼,然後執行/etc/rc.local;
由於執行rc0.d~rc6.d目錄下的運行層級指令碼是執行/etc/rc.d/rc指令碼執行的那麼我們就來看看這個指令碼
/etc/rc.d/rc指令碼說明:
#! /bin/bash
#
# rc This file is responsible for starting/stopping
# services when the runlevel changes.
#
# Original Author:
# Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
#
# check a file to be a correct runlevel script
check_runlevel ()
{
# Check if the file exists at all.
#判斷檔案存在,並可執行
[ -x "$1" ] || return 1
# Reject backup files and files generated by rpm.
#拒絕備份檔案格式的檔案名稱
case "$1" in
*.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig)
return 1
;;
esac
return 0
}
# Now find out what the current and what the previous runlevel are.
# 擷取到運行層級,如inittab中的/etc/rc.d/rc 0~6指定了運行層級,這兒的參數$1就是inittab中的命令傳的的參數0~6的數字
argv1="$1"
set `/sbin/runlevel`
runlevel=$2
previous=$1
export runlevel previous
#設定變數,當前運行層級,上一個運行層級
#如果沒有上一個運行層級,那麼previous=N
#載入/etc/init.d/functions指令碼,載入需要用到的函數定義
. /etc/init.d/functions
# See if we want to be in user confirmation mode
if [ "$previous" = "N" ]; then
if [ -f /var/run/confirm ] /
|| grep -i confirm /proc/cmdline >/dev/null ; then
rm -f /var/run/confirm
CONFIRM=yes
export CONFIRM
echo $"Entering interactive startup"
else
echo $"Entering non-interactive startup"
fi
fi
# Get first argument. Set new runlevel to this argument.
# 如果$argv1不是空串,賦予runlevel為argv1指定的運行級
[ -n "$argv1" ] && runlevel="$argv1"
# Is there an rc directory for this new runlevel?
# 如果沒有對應層級的rc($runlevel).d的目錄,那麼程式退出
[ -d /etc/rc$runlevel.d ] || exit 0# First, run the KILL scripts.
#在相應運行層級的rc($runlevel).d目錄下,遍曆以K開頭的檔案,逐個取出
#經過一系列判斷之後,執行指令碼,傳入stop參數
for i in /etc/rc$runlevel.d/K* ; do
check_runlevel "$i" || continue
#判斷檔案存在可
# Check if the subsystem is already up.
subsys=${i#/etc/rc$runlevel.d/K??}
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] /
|| continue
# Bring the subsystem down.
# 尋找在檔案中是否包含killproc和action單詞,-q選擇是不顯示輸入,只返回狀態
# 執行指令碼,傳入stop參數
if egrep -q "(killproc |action )" $i ; then
$i stop
else
action $"Stopping $subsys: " $i stop
fi
done
# Now run the START scripts.
#擷取/etc/rc($runlevel).d目錄下,以S開頭得檔案
#對每個檔案經過check之後,執行指令碼,傳入start參數
for i in /etc/rc$runlevel.d/S* ; do
check_runlevel "$i" || continue
# Check if the subsystem is already up.
subsys=${i#/etc/rc$runlevel.d/S??}
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] /
&& continue
# If we're in confirmation mode, get user confirmation
if [ -n "$CONFIRM" ]; then
confirm $subsys
case $? in
0) :;;
2) CONFIRM=;;
*) continue;;
esac
fi
# Bring the subsystem up.
if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then
export LC_ALL=C
exec $i start
fi
if egrep -q "(daemon |action |success |failure )" $i 2>/dev/null /
|| [ "$subsys" = "single" -o "$subsys" = "local" ]; then
$i start
else
action $"Starting $subsys: " $i start
fi
done
分析上面得rc指令碼,就不難理解,為什麼啟動指令碼在rc0~6.d目錄下要用S開頭命名,停止指令碼要在rc0~6.d目錄下要用K開頭命名.
我寫了一篇oracle自動啟動的文章,啟動的指令碼都是以S開頭,關閉的指令碼都是以K開頭,所以如果在編寫自動啟動程式,或者自動關閉程式的指令碼的時候,需要符合這個命名要求,才能被正確地執行.
- 使用者登入啟動
使用者登入之後會運行/etc/profile,在執行profile的時候,最後有一段代碼,如下:
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
. $i
fi
done
這段代碼將遍曆/etc/profile.d目錄,執行所有以*.sh(以sh結尾)檔案名稱的指令碼;
執行/etc/profile之後,然後執行使用者$HOME/.bash_profile指令碼
如果/etc/profile.d在目錄下建立以*.sh檔案名稱的指令碼,在每次使用者登入的時候都會啟動;而有些用程式只需啟動一次,不需要每次登入都啟動,如資料庫,web服務,應用伺服器等.使用者可以根據自己的情況,決定登入時啟動程式,還是主機啟動是啟動程式.
由於程式啟動並執行方式可能會不斷變化,有些使用者會把程式不斷地從一個目錄拷貝到另外一個目錄,名字也會不斷地修改,其實使用者只需要在一個地方存放應用程式,在配置目錄用ln -s建立一個阮串連就可以了;
- 退出時自動啟動
退出登入時候,將自動執行$HOME/.bash_logout檔案,如果在該命令中添加一些程式執行命令,在使用者退出登入時這些命令將被自動啟動.如,在該檔案最後添加:agentctl stop,表示退出的時候將執行該命令,停止apache服務.
- 一些shell開機檔案
$HOME/.bash_history 記錄使用者操作命令的記錄
$HOME/.bash_logout 使用者退出登入的時候執行這個指令碼
$HOME/.bash_profile 使用者登入,執行完/etc/profile之後執行.bash_profile(在unix下為.profile,linux下為unix)
$HOME/.bashrc shell 登入時自動執行
/etc/profile 每個使用者登入的時候都必須執行的指令碼
/etc/fstab 系統每次啟動的時候需要mount磁碟的操作資訊