Linux 基礎學習訓練教材 - RockyLinux 9.x

第 7 堂課:認識 bash 基礎與系統救援

文字界面的操作軟體就是 shell,預設 RockyLinux 使用的是 bash,所以一定要瞭解才行!另外,如何救援系統,也再次探討一下!

最近更新時間: 2023/02/26

前一節課談到檔案系統且最終有一個簡單的檔案系統錯誤救援。但如果發生嚴重問題時該如何是好?此時可能需要一個簡易的救援模式, 包括透過 systemd 以及直接取得一個 bash 來處理。而前面所有的章節,我們都會使用到的文字界面終端機,那就是 bash!這一小節, 我們將比較完整的介紹一下 bash 的相關用法,讓大家歸納一下之前學的東西,以及更深入討論看看!

7.1:bash shell 基礎認識

之前課程講過登入系統取得的文字型互動界面就稱為 shell,shell 的操作環境能夠依據使用者的喜好來設定,使用者也能夠切換不同的 shell。 而 shell 最重要的就是變數,這在許多的程式語言裡面都是需要注意到的部份。

7.1.1:系統與使用者的 shell

系統所有合法的 shell 都在 /etc/shells 這個檔案內,讀者可以查詢該檔案的內容。在 /etc/shells 常見的合法 shell 如下:

  • /bin/sh (已經被 /bin/bash 所取代)
  • /bin/bash (就是 Linux 預設的 shell)
  • /bin/tcsh (整合 C Shell ,提供更多的功能)
  • /bin/csh (已經被 /bin/tcsh 所取代)
我們的訓練機因為只安裝基礎的 Linux 系統,並沒有安裝 C shell,所以當你 cat /etc/shells 時,只有看到 bash 與 sh 而已喔! 如果有安裝 C shell 的話,那就會將額外的 shell program 寫入到這個檔案當中了!

因為有許多軟體會使用到系統上的 shell,但又擔心使用者或者是惡意攻擊者會使用怪異的有問題的 shell 來操作軟體。因此某些軟體在判斷 shell 的合法性, 亦即直接參考 /etc/shells 的規範,來判斷所謂的合法與不合法。

讀者從之前的系統登入行為中,應該知道在文字界面登入後系統會給予一個 shell,而在圖形界面時,也能夠藉由按下『終端機』來取得 shell 的操作。 但取得的預設 shell 是哪一個?需要從使用者的設定資料裡面搜尋。請參考 /etc/passwd 裡面,使用冒號 (:) 分隔的第 7 個欄位,就是該帳號預設取得的 shell。

例題 7.1.1-1:查詢合法的 shell 有哪些
  1. 請使用 cut 這個指令,將 /etc/passwd 這個檔案的內容中,以冒號 (:) 為分隔字元 (delimiter),將第 1 及第 7 欄位 (field) 輸出到螢幕上
  2. 承上,找到關鍵字為 daemon 的那一行,daemon 用戶所使用的 shell 是什麼?

使用者可以自由的切換所需要的 shell,不過不同的 shell 使用的方式、語法都有點差異。舉例來說, bash 使用的變數設定方式為 『var='content'』, 但是 csh 使用的是『 set var = 'content' 』,csh 需要有 set ,不過等號兩邊可以有空格。但是 bash 雖然不用 set ,但是等號兩邊不可以直接加空格, 這就有不一樣的的地方。

  • 不同 shell 的切換

其實, shell 就是一隻可以互動的程式而已,因此,基本上是可以互相呼叫而切換 shell 界面的!只是我們的 RockyLinux 9 預設只有安裝 bash 而已, 因此進行底下的測試之前,需要安裝額外的 shell 才行。

例題 7.1.1-2 :練習不同 shell 的切換
  1. 安裝額外的 C shell 界面:
    1. 請先啟用虛擬機器的網路環境,並確認網際網路為正常使用
    2. 使用 root 的身份,安裝 tcsh 這個軟體
    3. 確認一下 /etc/shells 有沒有加入 csh 成為合法的 shell 呢
  2. 在 bash 軟體環境下,操作確認 shell 名稱的指令:
    1. 請使用 student 身份登入系統,取得終端機後,使用『 echo $BASH 』的方式查閱有沒有這個變數以及其輸出的內容
    2. 請輸入『 echo $shell 』觀察有沒有資料輸出?
    3. 使用『 echo $0 』觀察輸出的資料是什麼?
  3. 切換到 c shell 查看一下確認 shell 名稱的指令:
    1. 使用『 /bin/csh 』切換 shell 成為 c shell
    2. 分別使用『 echo $BASH 』與『 echo $shell 』觀察輸出的資料為何?
    3. 使用『 echo $0 』觀察輸出的資料是什麼?
    4. 先透過『 exit 』離開 c shell 之後,再次以 echo $0 觀察目前的 shell 名稱為何?
  4. 執行『 /sbin/nologin 』看看輸出的資料為何?

使用者可以透過直接輸入 shell 的執行檔 (例如上述的 /bin/csh) 來直接切換到新的 shell 去工作,而想要確認目前的 shell 是什麼, 最簡單的方式就是使用『 echo $0 』列出目前的執行檔。 另外,系統的使用者帳號資料紀錄在 /etc/passwd 當中,該檔案裡面竟然有 /sbin/nologin 這個 shell 呢! 這個 shell 就是給系統帳號預設使用的不可互動的 shell !但是很奇怪,這個 /sbin/nologin 並沒有寫入 /etc/shells ,所以基本上,不能稱為合法的 shell 喔!

例題 7.1.1-3:嘗試修改用戶的預設 shell 程式 (使用 root 身份進行底下的處理)
  1. 用 usermod 來修改 student 的 shell 變成 /sbin/nologin
  2. 使用 su - student 之類的方式,嘗試切換身份成為 student
  3. 再次以 usermod 的方式將 student 的 shell 改回來 /bin/bash

為何系統上需要有 /sbin/nologin 這個 shell 呢?

  • 系統上面原本就有很多的軟體在執行,這些軟體各自有各自的功能,尤其是很多的服務軟體,需要的都是一些常駐程式 (daemon)。 這些 daemon 程式,最好都不要使用特權帳號 (指的就是 root 啦) 來執行,這樣在 daemon 不小心被攻破時,該程序的擁有者因為不是 root, 比較不會造成太大的系統危害。也因為這樣,Linux 裡面就有很多的系統帳號,包括前幾章都會用到的 sshd, bin, daemon 等帳號! 就是一些系統帳號啦!
  • 這些系統帳號畢竟還是 Linux 裡面的實體帳號~如果這些帳號被小心的給予密碼 (錯誤的設定),將可能造成某些人透過這些帳號嘗試登入/攻破你的 Linux 系統,因此,這些系統帳號,應該都是要給予限制的帳號 (restricted account)。所以,我們就給這些帳號無法互動的 shell! 那就是 /sbin/nologin 的用途!也就是,當你嘗試 su - daemon 時,系統會回報帳號無法使用囉!
  • 所謂的合法的 shell,也就是寫入到 /etc/shells 的殼程式們,一般來說,非限制的用戶 (unrestricted account) 所使用的 shell 就是合法的 shell 了!如果將 /sbin/nologin 寫入到 /etc/shells 裡面,那將代表 sshd, bin, daemon 等系統帳號具有合法的 shell, 即使這個 shell 是無法使用的~根據某些資安文件的說法,這很可能會造成一些漏洞攻擊的可能性。因此,預設的情況下, /sbin/nologin 不再寫入於 /etc/shells 當中了!(可以參考:https://access.redhat.com/errata/RHSA-2018:3249)
  • 另外,如果你建立的一般終端用戶,使用的服務並不包含取得可跟系統互動的 bash / csh 等,例如單純的 FTP / mail 帳號, 那也可以使用 /sbin/nologin 成為預設的 shell,這些終端帳號還是可以透過特別的設定,來取得 ftp, email 等服務的!
例題 7.1.1-4:建立系統帳號給予的 shell 方式
  1. 針對 /sbin/nologin 以及一般 shell program 的登入者差異:
    1. 使用 id 這個指令檢查系統有無 bin 與 student 這兩個帳號的存在?
    2. 能不能在不知道密碼的情況下,使用 root 切換成 student 這個帳號?為什麼?
    3. 能不能在不知道密碼的情況下,使用 root 切換成 bin 這個帳號?為什麼?
  2. 建立一個不能取得互動 shell 的帳號
    1. 建立一個不可登入系統取得互動 shell 的帳號,帳號名稱為 puser1,密碼為 MyPuser1
    2. 嘗試使用 root 切換成為這個帳號測試一下結果

7.1.2:變數設定規則

上一小節談到的『 echo $BASH 』就是變數的功能,bash shell 會主動的建立 BASH 這個變數,且其內容就是 /bin/bash, 方便讀者了解到目前的 shell 是哪隻程式達成的。那如何設定變數呢?簡單的設定方式與呼叫方式為:

[student@localhost ~]$ 變數="變數內容"
[student@localhost ~]$ echo $變數
[student@localhost ~]$ echo ${變數}

其中變數有許多的設定規則需要遵守:

  • 變數與變數內容以一個等號『=』來連結
  • 等號兩邊不能直接接空白字元
  • 變數名稱只能是英文字母與數字,但是開頭字元不能是數字
  • 變數內容若有空白字元可使用雙引號『"』或單引號『'』將變數內容結合起來
  • 承上,雙引號內的特殊字元如 $ 等,可以保有原本的特性
  • 承上,單引號內的特殊字元則僅為一般字元 (純文字)
  • 可用跳脫字元『 \ 』將特殊符號(如 [Enter], $, \, 空白字元, ' 等)變成一般字元
  • 在一串指令的執行中,還需要藉由其他額外的指令所提供的資訊時,可以使用反單引號『`指令`』或 『$(指令)』。
  • 若該變數為擴增變數內容時,則可用 "$變數名稱" 或 ${變數} 累加內容
  • 若該變數需要在其他子程序執行,則需要以 export 來使變數變成環境變數
  • 通常大寫字元為系統預設變數,自行設定變數可以使用小寫字元,方便判斷 (純粹依照使用者興趣與嗜好)
  • 取消變數的方法為使用 unset :『unset 變數名稱』
例題 7.1.2-1: 設定與呼叫變數 (使用 student 帳號操作)
  1. 設定一個名為 myname 的變數,變數的內容為『 peter pan 』
  2. 使用 echo 呼叫出 myname 的內容
  3. 是否能夠設定 2myname 的內容為『 peter pan 』呢?
  4. 設定 varsymbo 變數的內容為『 $myname 』,$myname 就是純文字資料不是變數 (不是 peter pan)。設定完畢後呼叫出來
  5. 設定 hero 變數的內容為『 I am $myname 』,其中 $myname 會依據 myname 變數的內容而變化。設定完畢請呼叫出來。
  6. 使用 uname -r 秀出目前的核心版本
  7. 設定 kver 變數,內容為『 my kernel version is N.xx 』,其中 N.xx 為 uname -r 輸出的資訊。請注意, kver 變數設定過程中,需要用到 uname -r 這個指令的協助,意思是,該項目為變動的!

變數設定的過程當中,使用子指令『 $(command) 』的操作為相當重要的。例如底下的案例中,管理員可以很快速的找到前一堂課談到的特殊權限檔案並列出該檔案的權限:

例題 7.1.2-2:透過子指令 $() 來處理資料的流程 (使用 student 帳號操作)
  1. 使用 man find 找出 -perm 的功能為何?
  2. 使用『 find /usr/bin /usr/sbin -perm /6000 』找出所有含有特殊權限的檔名
  3. 使用『 ls -l $(find /usr/bin /usr/sbin -perm /6000) 』將所有檔名的權限列出

如上的第 3 個範例,讀者可以將第 1 個範例的檔名找到後,一個一個以 ls -l 去查詢權限,不過效能與時間花費太多。 此時透過子指令的功能即可快速的找到相對應的資料。底下亦為常見的操作功能:

例題 7.1.2-3:同樣透過子指令來處理 (使用 student 帳號操作)
  1. 使用 find 的功能,找出在 /usr/sbin 及 /usr/bin 底下權限為 4755 的檔案
  2. 建立 ~/unit07/ 目錄
  3. 將步驟 1 找到的檔案連同權限複製到 ~/unit07 目錄下。

7.1.3:影響操作行為的變數

某些變數會影響到使用者的操作行為,許多變數之前曾經提及,本節集中說明。

變數功能
LANG
LC_ALL
語系資料,例如使用 date 輸出資訊時,透過 LANG 可以修改輸出的訊息資料。
PATH 執行檔搜尋的路徑~目錄與目錄中間以冒號(:)分隔,由於執行檔/指令的搜尋是依序由 PATH 的變數內的目錄來查詢,所以,目錄的順序也是重要的。
HOME 代表使用者的家目錄,亦即使用者看到的 ~ 代表的目錄。
MAIL 當我們使用 mail 這個指令在收信時,系統會去讀取的郵件信箱檔案 (mailbox)。
HISTSIZE 這個與『歷史命令』有關。我們曾經下達過的指令可以被系統記錄下來,而記錄的『筆數』則是由這個值來設定的。
RANDOM 『隨機亂數』的變數。目前大多數的 distributions 都會有亂數產生器,亦即 /dev/random 檔案。讀者可以透過這個亂數檔案相關的變數 ($RANDOM) 來隨機取得亂數。在 BASH 的環境下,RANDOM 變數的內容介於 0~32767 之間,所以,你只要 echo $RANDOM 時,系統就會主動的隨機取出一個介於 0~32767 的數值。
PS1 命令提示字元,可使用 man bash 搜尋 PS1 關鍵字,即可了解提示字元的設定方式。
? $? 這個變數內容為指令的回傳值,當回傳值為 0 代表指令正常運作結束,當不為 0 則代表指令有錯誤。

比較需要注意到的變數是 PATH 路徑搜尋變數,他會影響到使用者操作的行為,設定錯誤會有相當嚴重的後果。

例題 7.1.3-1: 關於 PATH 的重要性,不同帳號的使用
  1. 使用系統管理員的身份處理與設定相關變數資料:
    1. 印出 PATH 這個變數的內容,並觀察每個項目中間的分隔符號為何?
    2. 設定一個名為 oldpath 的變數,內容就是 ${PATH}
    3. 設定 PATH 的內容成為 /bin 而已 (非常重要,不可設錯!)
    4. 此時輸入以前曾操作過得 useradd --help 及 usermod --help 等指令,螢幕顯示的訊息為何?
    5. 若使用 /sbin/usermod --help,可以正常顯示嘛?
    6. 請設定 PATH 的內容成為 ${oldpath} ,恢復正常的路徑資料。
  2. 以一般帳號 student 的身份來執行下列的練習動作:
    1. 建立 ~student/cmd/ 目錄,且將 /bin/cat 複製成為 ~student/cmd/scat
    2. 輸入『 ~student/cmd/scat /etc/hosts 』確認指令正常無誤。
    3. 輸入『 scat /etc/hosts 』會發生什麼問題?
    4. 如何讓 student 用戶直接使用 scat 而不須使用 ~student/cmd/scat 來執行?
由於 PATH 設定錯誤時,可能會導致系統的 crash 狀態,尤其是當 PATH 並未含有 /bin 這個搜尋路徑時,有相當高的機率會造成 Linux 系統的當機。 因此,在上述的練習中,PATH 的設定請務必小心謹慎!

命令提示字元在每個系統中都不一樣,但那是可以修改的,就透過 PS1 這個變數來修改即可。

例題 7.1.3-2: 認識 PS1 這個變數的使用情境
  1. 呼叫出 PS1 這個變數的內容
  2. 請查詢上述變數內容當中 \W 及 \$ 的意義為何 (請 man bash 透過 PS1 關鍵字查詢)
  3. 假設操作者已經做了 15 個指令,則命令提示字元輸出如:『 [student@localhost 15 ~]$ 』該如何設定 PS1?

7.1.4:區域/全域變數、父程序與子程序

變數是有使用範圍的,一般來說變數的使用範圍分為:

  • 區域變數:變數只能在目前這個 shell 當中存在,不會被子程序所沿用
  • 全域變數:變數會儲存在一個共用的記憶體空間,可以讓子程序繼承使用。

如 7.1.2 當中提到的將變數提昇成為全域變數的方式為透過 export,觀察可用 env 或 export 來觀察。

例題 7.1.4-1: 了解區域變數、全域變數、父程序、子程序間的關係 (使用 student 帳號即可)
  1. 在父程序執行底下的動作,找尋區域變數與全域變數
    1. 使用 set 或 env 或 export 觀察是否存在 mypp 這個變數?
    2. 設定 mypp 的內容為『 from_ppid 』,並且呼叫出來
    3. 使用 set 或 env 或 export 觀察是否存在 mypp 這個變數?
  2. 變成子程序並持續討論變數:
    1. 執行『 /bin/bash 』進入下一個 bash 的子程序環境中
    2. 使用 set 或 env 或 export 觀察是否存在 mypp 這個變數?同時說明為什麼?
    3. 設定 mypp2 的內容為『 from_cpid 』,並且呼叫出來
    4. 使用『 exit 』離開子程序回到原本的父程序
  3. 在父程序處理全域變數,測試 export 的功能:
    1. 觀察是否存在 mypp2 這個變數?為什麼?
    2. 使用『 export mypp 』後,使用 env 或 export 觀察是否存在?
  4. 切換成為子程序,並確認全域變數的存在:
    1. 執行『 /bin/bash 』進入下一個 bash 的子程序環境中
    2. 使用 set 或 env 或 export 觀察是否存在 mypp 這個變數?同時說明為什麼?
    3. 回到原本的父程序中。

基本上,由原本的 bash 衍生出來的程序都是該 bash 的子程序,而 bash 可以執行 bash 產生一隻 bash 的子程序,兩隻 bash 之間僅有全域變數 (環境變數) 會帶給子程序, 而子程序的變數,基本上是不會回傳給父程序的。

7.1.5:使用 kill 管理程序

某些時刻管理員會有想要手動移除某些特定程序的時刻發生,例如某些很佔資源的 bash 程序的管理等等,此時就可以透過使用 kill 這個指令來處理。 基本上,kill 並不是『刪除』程序,而是給予程序一個『訊號 (signal) 』來管理,預設的訊號為 15 號,該訊號的功能為『正常關閉程序』的意思。 而想要強制關閉該程式,就得要使用 9 這個號碼來處理了。

例題 7.1.5:使用 kill 管理/傳送程序的訊號 (使用 student 身份)
  1. 使用『 vim checking.txt 』,隨便編輯幾個字,然後將 vim 程序放進背景中暫停
  2. 使用 jobs -l 進一步列出該程序的 PID 號碼
  3. 使用『 kill PID號碼 』嘗試刪除該工作,是否能夠生效?
  4. 若無法刪除,請使用『 kill -9 PID號碼 』的方式來刪除,是否能夠生效?
  5. 再次使用 vim checking.txt 時,會出現什麼訊息?如何解決?

若使用者有特別的需求需要刪除掉某些特定的程序,就可以透過這樣的機制來處理。

上面的例題內的動作只是測試而已,基本上不應該如此刪除資料!否則容易出問題!另外,由於某些網路莫名的緣故,透過網路進行 vim 編輯時,如果因為斷線而導致檔案來不及儲存,不要太擔心喔!透過上面的方式,可以『救援』回復一些資料!

7.1.6:login shell and non-login shell

當讀者下達『 echo ${PS1} 』時,應該有發現 PS1 這個影響操作行為的變數已經設定好了,故應該理解為已經有設定檔在協助使用者登入時規劃好操作環境的流程。 而讀者應該也會發現到,取得 bash 的情況有很多種,但大致可分為兩大類:

  • 一種是需要輸入帳號與密碼才能夠取得 bash 的行為,例如從 tty2 登入,或者是輸入『 su - 』來取得某個帳號的使用權,這種情況被稱為是 login shell 的變數設定檔讀取方式。
  • 一種是使用者已經取得 bash 或者是其他的互動界面,然後透過該次登入後執行 bash ,例如從圖形界面按下終端機、直接在文字界面輸入 bash 來取得 bash 子程序、輸入『 su 』來切換身份等等,這種方式通常不需要重新輸入帳號與密碼,因此稱為 non-login shell 的變數設定檔讀取方式。

通常 login shell 讀取設定檔的流程是:

  1. /etc/profile:這是系統整體的設定,你最好不要修改這個檔案;
  2. ~/.bash_profile 或 ~/.bash_login 或 ~/.profile (只會讀 1 個,依據優先順序決定):屬於使用者個人設定,你要改自己的資料,就寫入這裡!

由於 login shell 已經讀取了 /etc/profile 因此已經設定了大部分的全域變數設定,所以 non-login shell 只需要少部份的設定即可。 故 non-login shell 只會讀取一個個人設定檔,亦即是:

  • ~/.bashrc
例題 7.1.6-1:理解 login shell 與 non-login shell 的環境參數讀取行為
  1. 觀察一下 ~/.bash_profile 的內容,說明該檔案設定了什麼項目?
  2. 觀察 ~/.bashrc 的內容,說明該檔案設定了什麼項目?

由於 ~/.bash_profile 也是讀取 ~/.bashrc ,因此使用者只需要將設定放置於家目錄下的 .bashrc 就可以讓兩者讀取了。

事實上,也建議你可以前往 /etc/profile 這個檔案內容瞧一瞧,看看到底 login shell 讀了哪些設定檔喔!
例題 7.1.6-2:嘗試設定 student 的操作環境
  1. 請在 student 的家目錄編輯 .bashrc ,增加底下的項目:
    1. 設定 history 可以輸出 10000 筆資料
    2. 設定執行 cp 時,其實會主動加入 cp -i 的選項
    3. 設定執行 rm 時,其實會主動加入 rm -i 的選項
    4. 設定執行 mv 時,其實會主動加入 mv -i 的選項
    5. 增加 PATH 的搜尋目錄在 ~/cmd 目錄 (模仿 .bashrc ,避免重複出現!)
    6. 設定一個變數名稱為 kver,其內容是目前的核心版本
    7. 強迫語系使用 zh_TW.utf8 這個項目,且必須要設定為全域變數
    8. 讓提示字元項目中,增加時間與操作指令次數的項目。
    9. 使用 wc 指令分析 ~/.bash_history 的行數,將該行數紀錄於 h_start 的變數中
  2. 設定完畢後,如何在不登出的情況下,讓設定生效?

當使用者登出 bash 時,bash 會依據家目錄下的 .bash_logout 來進行後續的動作,因此若使用者有需要額外進行某些工作時, 可以在此檔案中設定。

不過使用者應該要特別注意的, .bash_logout 僅會在 login-shell 的環境下,登出才會執行。在 non-login shell 的環境下登出, 這個檔案並不會被運作的。

例題 7.1.6-3: 處理 logout 額外執行的任務
  1. 每次登出 bash 時,都會:
    1. (1)使用 date 取得『 YYYY/MM/DD HH:MM 』的格式,並且轉存到家目錄的 history.log 檔案中
    2. (2)使用 history 加上管線命令與 wc 來分析結束時的 history 行數,將該數值設定為 h_end,搭配之前設定的 h_start 開始的行數, 計算出這次執行指令的行數號碼 (應該是 h_end - h_start +1 ),設定為 h_now,透過 history ${h_now} 將最新的指令轉存到 history.log 當中。
  2. 嘗試使用 su - student 來登入 student ,再隨意進行數個指令,之後登出 bash 回到原本的 bash 當中,觀察 ~/history.log 是否有資訊紀錄?

7.2:系統救援

我們在前一堂課提到過簡易的系統救援,直接以 root 的密碼與身份來進入救援模式,然後處理好了檔案系統。但萬一 root 的 shell 被不小心修改了, 導致無法使用 root 的密碼進入系統時,該如何處理?底下的動作比較嚴重,請讀者務必要學會救援的方式。

7.2.1:透過正規的 systemd 方式救援

我們前面講過許多重要的系統管理,其中包括檔案系統與這節課提到的 shell 功能。想一想,如果產生底下的問題時,該如何處理?

  • 檔案系統或者是 /etc/fstab 設定檔寫錯了!
  • root 的 shell 被誤改成為 nologin,導致無法使用 root 了 (即使知道密碼)

要處理這個練習,請先進行如下的動作之後,讓系統被破壞,才能夠加以練習:

[root@localhost ~]# vim /etc/fstab
/dev/mapper/rocky-home1 /home  xfs  defaults  0 0

[root@localhost ~]# usermod -s /sbin/nologin root
[root@localhost ~]# su -
This account is currently not available.

如此才能夠確認 1. 檔案系統被破壞以及 2. root 的身份設定錯誤 (shell 無法使用)。接下來執行 reboot 來看看會出現什麼問題。

圖 7.2.1-1、因為檔案系統與 root 身份出問題的狀態
圖 7.2.1-1、因為檔案系統與 root 身份出問題的狀態

如上圖所示,開機後出現檔案系統狀態,系統要求輸入 root 密碼,雖然用戶輸入正確的密碼了,卻無法取得 root 的 bash 操作界面, 因為設定到錯誤的 shell 了。此時正規的救援模式無法使用,需要用到 systemd 開機流程裡面,讓系統進入到一個小小的救援作業系統, 該作業系統是模擬出來的,僅僅用來作為掛載檔案系統的功能。處理的流程為:

  1. 重新開機,且進入選單後的五秒內按下方向鍵,並將光棒選擇到第一個開機選單項目上面
    圖 7.2.1-2、光棒的移動與進入編輯模式的參考按鈕 (e)
    圖 7.2.1-2、光棒的移動與進入編輯模式的參考按鈕 (e)
  2. 按下『 e 』來進入選單編輯畫面,如下所示,並且在 linux 那一行的最後面增加『 rd.break 』的項目,之後按下 [Ctrl]+x 來進入救援模式
    圖 7.2.1-3、互動編輯核心參數,加入進入救援模式的方案
    圖 7.2.1-3、互動編輯核心參數,加入進入救援模式的方案
  3. 救援模式會將根目錄掛載到 /sysroot 這個目錄下,不過是預設掛載成唯讀,因此管理員請用『 mount -o remount,rw /sysroot 』將該目錄重新掛載成可讀寫, 然後使用『 chroot /sysroot 』將根目錄切換到 /sysroot 底下,就可以成功的取用原本的作業系統了。
    圖 7.2.1-4重新掛載為可讀寫,並進行更換根目錄的行為 (chroot) 圖 7.2.1-4重新掛載為可讀寫,並進行更換根目錄的行為 (chroot) 圖 7.2.1-4重新掛載為可讀寫,並進行更換根目錄的行為 (chroot)
    圖 7.2.1-4重新掛載為可讀寫,並進行更換根目錄的行為 (chroot)
  4. 此時系統提示字元只有『 sh-5.1# 』也是正常的,請執行『 mount -a 』之後就可以進行『 usermod -s /bin/bash root 』等動作!一般建議動作流程如下:
    [root@localhost ~]# mount -a
    [root@localhost ~]# usermod -s /bin/bash root
    [root@localhost ~]# vim /etc/fstab
    /dev/mapper/rocky-home /home  xfs  defaults  0 0
    
    [root@localhost ~]# touch /.autorelabel 
    [root@localhost ~]# exit
    
  5. 最後使用 reboot 重新開機,就能夠正常的開機進入系統環境了。

最後一個步驟之所以要處理 /.autorelabel 這個情況,是因為 Rocky Linux 9 預設會啟用 SELinux 這個安全強化模組,但是此模組在救援模式並沒有開啟, 所以被更動到的檔案在下次開機後,可能會產生無法讀取的問題。系統開機會去找 /.autorelabel ,若發現有此檔案則會重新寫入 SELinux 的相關設定, 因此系統在重新開機的流程中共會啟動兩次,原因為第一次會重新寫入 SELinux 設定,第二次才是正常開機。

圖 7.2.1-4、SELinux 的重設過程
圖 7.2.1-4、SELinux 的重設過程
根據上課的經驗,filesystem 的問題與 user 的問題最好於一次 rd.break 的救援流程中解決,否則由於現有的 Linux 系統程序為平行處理, 若卡在 /home 偵測過 90 秒後,再次進入給予 root 密碼的程序中,就會由於無法跑到系統重整 (./autolabel 的動作要求),導致帳號資料密碼檔無法被讀取, 此時系統會 crash 。

7.2.2:透過 bash 直接救援 (Optional)

若讀者以前有接觸過 Linux 的話,應該知道開機流程中,可以使用 init=/bin/bash 直接讓核心呼叫 bash 來操作系統。 Rocky Linux 9 的 grub2 與 systemd 也保留此功能,此操作行為與 rd.break 相當接近。

  1. 同樣在開機過程中,使用第一個開機選單,然後按下 e 來進入互動編輯模式
  2. 在 linux 那一行的最後面加入 init=/bin/bash 然後按下 [ctrl]+x 來啟動
  3. 出現『 bash-5.1# 』之後,進行如下的動作來處理:
    [root@localhost ~]# mount -o remount,rw /
    [root@localhost ~]# mount -a
    [root@localhost ~]# /usr/sbin/usermod -s /bin/bash root
    [root@localhost ~]# /usr/bin/vim /etc/fstab
    [root@localhost ~]# /usr/bin/touch /.autorelabel 
    [root@localhost ~]# /usr/sbin/reboot -f
    
圖 7.2.2-1、直接使用 bash 救援!
圖 7.2.2-1、直接使用 bash 救援!

這個方案讓 Linux 核心主要去呼叫 bash 來執行,因為核心預設使用 root 權限,所以呼叫的 bash 就會是 root 用戶來操作。 只是因為非正規使用這個 bash 環境,所以連 PATH 恐怕都沒有完整的載入!因此操作指令時,就得要使用絕對路徑來處理。 另外,也因為系統非正規使用,所以不是使用預設的 systemd,不能直接使用 reboot 來重新開機。不過還好, reboot 可以加上 -f (/usr/sbin/reboot -f) 來略過 systemd 的控制,這樣就可以直接重新開機了!

除非正常流程已經無法解決,否則盡量不要使用此方法救援。

7.3:課後練習操作

  • 上課的課後練習,非作業:
  1. 變數的相關操作 (全部用 root 身份進行)
    1. 將 /bin/false, /bin/true 等檔案設定為系統合法的 shell
    2. 使用 usermod -s [tab][tab] 出現什麼?可能的意義是什麼?
    3. 將 /bin/false, /bin/true 移除合法 shell 的列表中。
    4. 查看目前 /etc/passwd 當中,有哪些帳號是可以使用 bash 登入系統的?
    5. 目前有哪些全域變數存在
    6. 顯示出 PS1 的內容
    7. 將 PS1 的內容改成類似『 C:\win> 』,再測試看看,測試完畢就改回原本的 PS1 喔
    8. 顯示出目前的 PATH 內容
    9. 讓 PATH 延伸到支援 /opt/bin 目錄
    10. 設定 kver 為 uname -r 的輸出結果
    11. 將 kver 設定成為全域變數
    12. 由 man 7 signal 找到 1 號是在幹麻的?
    13. 透過上述的功能,找到 rsyslog 這個軟體的 PID,並對他下達 signal 1 的訊號
    14. 查看一下 /var/log/messages 出現了什麼訊息?
    15. 再由 man 7 signal 找到 SIGTSTP 與 SIGINT 分別是幾號?其中 SIGINT 其實是 [ctrl]+c 而 SIGTSTP 就是 [ctrl]+z 的意思。
    16. 開另外一個 bash 視窗,並且啟用 vim 軟體
    17. 由原本的 root 環境,找到 vim 的 PID,並且嘗試將該 PID 放入背景暫停中,並查閱另一個視窗的結果
    18. 使用 $(( )) 的功能,計算一天共有幾秒鐘?
  • 作業 (不提供學生答案,僅提供教師參考答案)

作業硬碟一般操作說明:

  • 開啟雲端虛擬機器前,請務必確認你開啟的硬碟是『unit07』,否則就會做錯題目
  • 若要使用圖形界面,請務必使用 student 身份登入,若需要切換身份,再啟用終端機處理。
  • 若有簡答題需要使用中文,請自行以第一堂課的動作自行處理輸入法安裝。
  • 每部虛擬機器均有獨特的網卡位址,請勿使用他人硬碟上傳,否則計分為 0 分。
  • 每位同學均有自己的 IP 尾數,請先向老師詢問您的 IP 尾數,才可以進行作業上傳。
  • 最終上傳作業結果,請務必使用 root 身份上傳。
  • 進入作業硬碟後,先用 root 身份執行 vbird_book_setup_ip , 執行流程請參考:vbird_book_setup_ip

作業當中,某些部份可能為簡答題~若為簡答題時,請將答案寫入 /home/student/ans.txt 當中,並寫好正確題號,方便老師訂正答案。 請注意,檔名寫錯將無法上傳!

請使用 root 的身份進行如下實做的任務。直接在系統上面操作,操作成功即可,上傳結果的程式會主動找到你的實做結果。

  1. (30%) 整體作業系統救援:
    • 問題: 因為某些緣故,目前這個作業系統應該是無法順利開機的。請使用本節課程所介紹的方式來進行系統的救援。
    • 思考: 根據猜測,可能的原因與 (1)管理員曾經動過 chsh 這個指令有關, (2)管理員似乎也更動過 fstab 這個設定檔。
    • 救援: 請依據這些之前的可能舉動,來恢復系統的可登入狀態。
    • 注意提醒: 千萬不要忘記 .autorelabel 的動作!
    • 成功開機登入後: 順利登入系統後,再使用 root 身份處理 vbird_book_setup_ip 的腳本設定。
  2. (10%) 請處理底下帳號與 shell 的相關事宜:
    1. (3%) 請將系統中的 /bin/false 與 /bin/true 這兩個檔案變成合法的 shell
    2. (3%) 請將 examuser1 的 shell 變成 /bin/true
    3. (4%) 因為你即將建立一個 FTP 伺服器,這個伺服器上面的用戶只能單純的使用 FTP 功能,因此你想要讓這些帳號無法使用 shell。 假設兩個帳號名為 myuser1, myuser2 的帳號,這兩個帳號將無法使用互動界面操作系統,且密碼均為 MyPassWordhehe
  3. (10%) 透過 bash shell 的功能,進行檔案的查詢與複製
    1. (5%) 找出系統中檔案擁有者為 examuser1 的檔名,並將這些找到的檔名(含權限)複製到 /root/findout/ 目錄內
    2. (5%) 找出在 /usr/sbin 及 /usr/bin 底下權限為 4755 的檔案,並將這些檔案複製到 /root/findperm/ 目錄內
  4. (5%) 寫一隻『大家都能執行的腳本程式』,執行名稱為:『 myps 』,執行該指令,其實輸出為資料是:『 ps -eo pid,pri,ni,args 』。 請注意: (1)這隻程式定義為『本機全部用戶都能執行』,所以應該與 bin 有關,不是 sbin! (2)使用者在任何工作目錄,只要在提示字元輸入 myps 即可獲得『ps -eo pid,pri,ni,args』的輸出結果。
  5. (45%) 特別的帳號成立行為要處理的:
    1. (3%) 建立名為 examuser10 的帳號,密碼為 MyPassWordhehe,且這個帳號登入後,預設會有後續的一些基礎設定
    2. 登入行為:(注意,如果用戶的 shell 不是 bash,那這個題組就算全錯喔!)
      1. (3%) 預設使用 bash 作為 shell
      2. (3%) 會讀入 /etc/examvar 設定檔
      3. (3%) 擁有一個名為 myip 的變數,變數內容為『 ifconfig | grep 'inet ' | cut -d 't' -f 2 | cut -d ' ' -f 2 』 的執行成果 (每個同學操作指令的結果都不會相同,但是指令會是一樣的)
      4. (3%) 使用 C 語系資料
      5. (3%) 增加 ~examuser10/scripts/ 目錄作為指令執行時所尋找的目錄位置
      6. (3%) 命令提示字元增加時間項目在裡面 (提示字元有點像『[examuser10@localhost 14:37:31 ~]# 』)
      7. (3%) 預設歷史命令紀錄 5000 筆,檔案紀錄也會是 5000 筆
      8. (3%) 操作 cp 時,自動給予 cp -i 的選項
      9. (3%) 透過『 wc -l ~/.bash_history | cut -d ' ' -f 1 』的指令取得前一次登入的歷史命令次數, 並將該數值轉存到 ~/.history_start 檔案內(這個檔案每次都覆蓋)
    3. 登出的行為:
      1. (3%) 透過『 history | tail -n 1 | awk '{print $1}' 』取得最後一筆歷史紀錄,然後將該數值指定為 hist_end 變數
      2. (3%) 請使用『 cat ~/.history_start 』取得登入時記載的歷史命令筆數,將該數值指定為 hist_start 變數
      3. (3%) 設定一個名為 hist_size 的變數,內容為 hist_end - hist_start 的數值 (有多種計算方式,能成功即可!)
      4. (3%) 將離開的日期,使用『 YYYY/MM/DD HH:MM 』的格式累加寫入到 ~/history.log 檔案中
      5. (3%) 透過『 history $hist_size 』取得最後最新的數筆紀錄後,將該資料累加到 ~/history.log 檔案中。

作業結果傳輸:請以 root 的身分執行 vbird_book_check_unit 指令上傳作業結果。 正常執行完畢的結果應會出現【XXXXXX_aa:bb:cc:dd:ee:ff_unitNN】字樣。若需要查閱自己上傳資料的時間, 請在作業系統上面使用瀏覽器查詢: http://192.168.251.254 檢查相對應的課程檔案。 相關流程請參考: vbird_book_check_unit

修改歷史:
  • 2023/02/26:修改了 /sbin/nologin 的說明,重新 rockylinux 救援畫面截圖,同時修訂了 reboot -f 的功能!
2023/02/26 以來統計人數
計數器
其他連結
環境工程模式篇
鳥園討論區
鳥哥舊站

今日 人數統計
昨日 人數統計
本月 人數統計
上月 人數統計