章 3. FreeBSD 基礎

3.1. 概述

接下來的這一章將涵蓋 FreeBSD 作業系統的基本指令及功能。 大部份的內容在 UNIX™-like 作業系統中都是相通的。 如果您對這些內容熟悉的話,可以放心的跳過。 如果您剛接觸 FreeBSD,那您一定要仔細的讀完這章。

讀完這章,您將了解:

  • 如何使用 FreeBSD 的虛擬 Console。

  • 如何在 FreeBSD 建立與管理使用者與群組。

  • UNIX™ 檔案權限以及 FreeBSD 檔案標記的運作方式。

  • 預設的 FreeBSD 檔案系統配置。

  • FreeBSD 的磁碟組織。

  • 如何掛載 (Mount)、卸載 (Umount) 檔案系統。

  • 什麼是程序、Daemon 以及信號 (Signal)。

  • 什麼是 Shell,以及如何變更您預設的登入環境。

  • 如何使用基本的文字編輯器。

  • 什麼是裝置 (Device) 和裝置節點 (Device node)。

  • 如何閱讀操作手冊以獲得更多的資訊。

3.2. 虛擬 Console 與終端機

如果您沒有將 FreeBSD 設定成開機時自動進入圖形化模式,系統會進入指令登入提示像是這樣的東西:

FreeBSD/amd64 (pc3.example.org) (ttyv0)

login:

第一行包含了剛開機完系統的資訊,amd64 代表此範例所使用的系統是執行 64-位元版本的 FreeBSD,這台主機的名稱是 pc3.example.orgttyv0 代表這是個 "系統 Console"。第二行則是登人的提示訊息。

FreeBSD 是一個多使用者的系統,需要一套可以分辨不同使用者的方法。因此所有的使用者在執行程式之前必須先"登入"系統以取得系統內程式的存取權限。每個使用者都有一組獨一無二的使用者名稱 ("username") 及個人密碼 ("password")。

要登入系統 Console 需輸入在系統安裝時設定的使用者名稱,請參考 新增使用者,並按下 Enter。 接著輸入該使用者名稱的密碼按下 Enter。 輸入的密碼為了安全起見不會顯示在畫面上。

如果您輸入了正確的密碼,您應該會看到今日訊息 (Message of the day, MOTD),後面接著顯示指令提示字元,依使用者建立時所選擇的 Shell 會有不同的提示字元可能為 #, $ 或者 %。 看到指令提示代表使用者現在已經登入 FreeBSD 系統 Console 且已經準備好可以下指令。

3.2.1. 虛擬 Console

雖然系統 Console 已經可以用來與系統互動,但使用鍵盤來下指令使用 FreeBSD 系統的使用者通常會使用虛擬 Console 登入。 因為系統訊息預設會顯示在系統 Console,這些訊些會在使用者作業的過程中不斷出現,讓使用者難以專心作業。

FreeBSD 預設提供多個虛擬 Console 可輸入指令,每個虛擬 Console 都有自己的登入提示及 Shell 並且可以輕易的在虛擬 Console 間切換。 這實際上讓指令輸入有了類似於圖型化環境中可以同時開啟多個視窗的功能。

組合鍵 Alt+F1Alt+F8 被 FreeBSD 保留用來切換虛擬 Console,使用 Alt+F1 可切換至系統 Console (ttyv0),Alt+F2 可存取第一個虛擬 Console (ttyv1),Alt+F3 可存取第二個虛擬 Console (ttyv2),以此類推。當使用 Xorg 作為圖型化 Console 時,組合鍵則改使用 Ctrl+Alt+F1 來切換回文字介面的虛擬 Console。

當您從一個 Console 切換到下一個的時候,FreeBSD 會切換畫面顯示的內容, 這就好像有很多虛擬的螢幕和鍵盤可以讓您輸入指令到 FreeBSD 執行。 在某一個虛擬 Console 上執行的程式並不會因為使用者切到別的 Console 而停止執行。

請參考 kbdcontrol(1), vidcontrol(1), atkbd:(4), syscons(4) 以及 vt(4) 來取得更多有關 FreeBSD Console 及鍵盤驅動程式的技術說明。

FreeBSD 中虛擬 Console 的數量設定在 /etc/ttys 檔案中的下列章節:

# name    getty                         type  status comments
#
ttyv0   "/usr/libexec/getty Pc"         xterm   on  secure
# Virtual terminals
ttyv1   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv2   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv3   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv4   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv5   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv6   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv7   "/usr/libexec/getty Pc"         xterm   on  secure
ttyv8   "/usr/X11R6/bin/xdm -nodaemon"  xterm   off secure

要關閉虛擬 Console 只要在指定的虛擬 Console 該行設定的一開始加上註解符號 ()。 例如要將虛擬 Console 的數量由 8 個改為 4 個,則可將 加在代表虛擬 Console 的 ttyv5ttyv8 的最後四行一開始。 請勿將系統 Console ttyv0 加上註解符號。 注意,若有依照 X Window 系統 安裝並設定 Xorg 時,會用到最後一個虛擬 Console (ttyv8)。

有關各欄位的設定以及其他選項,請參閱 ttys(5) 說明。

3.2.2. 單使用者模式

FreeBSD 開機選單會提供一個選項為 "Boot Single User",若選擇該項目,系統將會進入所謂 "單使用者模式" 的特殊模式。 此模式通常用在修復系統無法開機或重設已忘掉的 root 密碼。 在當使用者模式中無法使用網路及其他虛擬 Console,但有完整 root 對系統的存取權限,而且預設是不須要輸入 root 密碼。 也因此,要能透過實體鍵盤操作才能進入此模式,在考量 FreeBSD 系統安全時須要限制可操作實體鍵盤的人員。

有關單使用者模式的設定可在 /etc/ttys 中的以下章節中找到:

# name  getty                           type  status  comments
#
# If console is marked "insecure", then init will ask for the root password
# when going to single-user mode.
console none                            unknown  off  secure

預設狀態為安全 (secure),這代表誰能夠操作實體鍵盤不是不重要就是已受到實體安全規範管制。 若設定更該為不安全 (insecure) 則代表主機所在的環境不安全,因為任何人皆可接觸鍵盤。 當此行設定更改為不安全 (insecure) 時,當使用擇選擇單使用者模式時,FreeBSD 將會要求輸入 root 的密碼。

請審慎考慮是否要改為 insecure! 因為萬一忘記 root 密碼的話,雖然還是有其他辦法可以登入單使用者模式,只是對不熟 FreeBSD 開機程序的人可就麻煩了。

3.2.3. 更改 Console 影像模式

FreeBSD Console 預設顯示大小可以調整為 1024x768、1280x1024 或其他顯示卡與螢幕有支援的解析度大小。 要使用不同的影像模式需載入 VESA 模組:

# kldload vesa

要偵測硬體支援的影像模式,可使用 vidcontrol(1)。 要取得支援的影像模式清單可輸入以下指令:

# vidcontrol -i mode

該指令會顯示硬體所支援的影像模式清單,要採用新的影像模式需以 root 使用者執行 vidcontrol(1) 指令:

# vidcontrol MODE_279

若可接受新的影像模式,可以在 /etc/rc.conf 加入設定,讓每次重開機後會自動生效:

allscreens_flags="MODE_279"

3.3. 使用者與基礎帳號管理

FreeBSD 允許多使用者同時使用電腦,在一次只能有一位使用者坐在電腦螢幕前使用鍵盤操作的同時,可讓任何數量的使用者透過網路登入到系統。每一位要使用該系統的使用者應有自己的帳號。

本章介紹:

  • FreeBSD 系統中各種類型的使用者帳號。

  • 如何加入、移除與修改使用者帳號。

  • 如何設定用來控制使用者與群組允許存取的資源的限制。

  • 如何建立群組與加入使用者作為群組成員。

3.3.1. 帳號類型

由於所有對 FreeBSD 系統的存取是透過使用者帳號來達成,且所有的程序需要經由使用者來執行,因此使用者帳號管理非常重要。

有三種主要類型的帳號:系統帳號、使用者帳號以及超級使用者帳號。

3.3.1.1. 系統帳號

系統帳號用來執行服務,例如 DNS、郵件及網頁伺服器,要這麼作是因為安全性考量,若所有的服務均以超級使用者來執行,那麼這些服務的運作將不會受到限制。

系統帳號的例子有 daemon, operator, bind, news, and www

nobody 是通用的無權限系統帳號。雖然如此,只有要越多的服務使用 nobody,就會有更多的檔案與程式與該使用者相關聯,會讓該使用者擁有更多的權限。

3.3.1.2. 使用者帳號

使用者帳號會分配給實際人員,用來登入及使用系統。每位要存取系統的人員需要擁有一組唯一的使用者帳號,這可讓管理者辨識誰在做什麼以及避免使用者覆蓋其他使用者的設定。

每位使用者可以設定自己的環境來配合自己使用系統的習慣,透過設定預設的 Shell、編輯器、組合鍵 (Key Binding) 及語言設定。

每個在 FreeBSD 系統的使用者帳號都會有一些相關的資訊:

使用者名稱 (User name)

login: 提示出現時便要輸入使用者名稱,每位使用者必須要有一個唯一的使用者名稱。要建立有效的使用者名稱要遵守數條規則,在 passwd(5) 中有說明。建議使用者名稱由 8 個或更少的字母組成,全部採用小寫字元以向下相容應用程式。

密碼 (Password)

每個帳號都會有密碼。

使用者 ID (UID)

使用者 ID (User ID, UID) 是一組數字用來獨一無二的辨識 FreeBSD 系統的使用者,用到使用者名稱的指令會先將使用者名稱轉換為 UID。建議使用小於 65535 的 UID,超過這個值可能會造成部份軟體的相容性問題。

群組 ID (GID)

群組 ID (Group ID, GID) 是一組數字用來獨一無二的辨識使用者所屬的主要群組。群組是一個除了使用 UID 之外根據使用者的 GID 來控制資源存取權的機制。這可以顯著的降低某些設定檔的大小且可讓使用者成為一個以上群組的成員。建議使用 65535 或以下的 GID,因超過此值的 GID 可能會讓部份軟體無法運作。

登入類別 (Login class)

登入類別 (Login class) 擴充了群組機制,當在對不同使用者客製化系統時可提供額外的彈性。在 設定登入類別 有對登入類別更進一步的討論。

密碼更改時間 (Password change time)

預設情況下密碼並不會過期,雖然如此,密碼期限可在各別使用者上開啟,可強制部份或所有使用者在某段期間過後更改他們的密碼。

帳號到期時間 (Account expiration time)

預設情況下 FreeBSD 的帳號不會有期限。當建立需要有限壽命的帳號時,例如,學校的學生帳號,可使用 pw(8) 指定帳號的到期日期。到期日期過後,便無法使用該帳號登入到系統,儘管該帳號的目錄及檔案仍存在。

使用者的全名 (User’s full name)

使用者名稱用來獨一無二的辦識 FreeBSD 的帳號,但並不一定反映了使用者的真實姓名。類似註解,這個資訊可以含有空白、大寫字元並可超過 8 個字母的長度。

家目錄 (Home directory)

家目錄是系統中某個目錄的完整路徑,這個目錄是使用者登入後的起點目錄。習慣上會將所有使用者目錄放置在 /home/username/usr/home/username。每位使用者可以儲存他們的個人檔案及子目錄於他們自己的家目錄。

使用者 Shell (User shell)

Shell 提供了使用者預設的環境來與系統互動。有數種不同類型的 Shell,有經驗的使用者會有自己偏好的選擇,可儲存在自己的帳號設定。

3.3.1.3. 超級使用者帳號

超級使用者帳號,通常稱作 root,用來管理系統,沒有權限的限制,也因這個原因,該帳號不應該用來做每日的例行作業,如:寄信與收信、系統的一般探索或程式設計。

超級使用者並不像其他使用者帳號,可以沒有限制的操作,不正確的使用超級使用者帳號可能會造成可觀的災害。一般使用者帳號不會因為失誤而法摧毀作業系統,所以建議登入一般使用者帳號,只有在指令需要額外權限時切換為超級使用者。

使用超級使用者下指令時永遠要再三檢查,由於一個多餘的空白或缺少的字元可能意味著無法挽回的資料遺失。

有數種方法可以提升為超級使用者權限,雖然可以直接登入為 root,但強烈不建議這樣做。

改使用 su(1) 切換為超級使用者。執行此指令時若指定 - 參數,該使用者會繼承 root 的使用者環境。執行此指令的使用者必須在 wheel 群組中,否則指令會失敗。使用者也必須要知道 root 使用者帳號的密碼。

在此例當中,該使用者只在要執行 make install 時切換為超級使用者,因為這個步驟需要超級使用者權限。指令完成之後,該使用者輸入 exit 離開超級使用者帳號並返回他的使用者帳號權限。

例 1. 以超級使用者的身份安裝程式
% configure
% make
% su -
Password:
# make install
# exit
%

內建的 su(1) 框架在單人系統或只有一位系統管理者的小型網路可以運作的很好。另一種方式是安裝 security/sudo 套件或 Port。此軟體提供了活動記錄且允許管理者設定那個使用者可以用超級使用者執行那個指令。

3.3.2. 管理帳號

FreeBSD 提供了各種不同指令來管理使用者帳號,最常用的指令已摘要於 管理使用者帳號的工具,接著有一些用法的範例。請參考每個工具的操作手冊來取得更多詳細的資訊與用法範例。

表 1. 管理使用者帳號的工具
指令摘要

adduser(8)

建議用來新增新使用者的指令列應用程式。

rmuser(8)

建議用來移除使用者的指令列應用程式。

chpass(1)

用來更改使用者資料庫資訊的工具。

passwd(1)

用來更改使用者密碼的指令列工具。

pw(8)

用來修改使用者帳號各方面資訊強大且靈活的工具。

3.3.2.1. adduser

建議用來新增新使用者的程式為 adduser(8)。當新使用者新增之後,此程式會自動更新 /etc/passwd 以及 /etc/group,這同時也會建立新使用者的家目錄 (複製 /usr/shared/skel 中的預設設定檔),並且可以選擇是否要寄送歡迎訊息通知新使用者。這個工具必須使用超級使用者執行。

adduser(8) 工具採用互動的方式,只需幾個步驟便可建立新使用者帳號。如 在 FreeBSD 新增使用者 所示,可輸入必填的資訊或按 Return 鍵採用方括中的預設值。在此例當中,使用者被邀請加入 wheel 群組,這讓使用者可使用 su(1) 變成超級使用者。完成之後,此工具會詢問是否要建立其他的使用者或離開。

例 2. 在 FreeBSD 新增使用者
# adduser
Username: jru
Full name: J. Random User
Uid (Leave empty for default):
Login group [jru]:
Login group is jru. Invite jru into other groups? []: wheel
Login class [default]:
Shell (sh csh tcsh zsh nologin) [sh]: zsh
Home directory [/home/jru]:
Home directory permissions (Leave empty for default):
Use password-based authentication? [yes]:
Use an empty password? (yes/no) [no]:
Use a random password? (yes/no) [no]:
Enter password:
Enter password again:
Lock out the account after creation? [no]:
Username   : jru
Password   : ****
Full Name  : J. Random User
Uid        : 1001
Class      :
Groups     : jru wheel
Home       : /home/jru
Shell      : /usr/local/bin/zsh
Locked     : no
OK? (yes/no): yes
adduser: INFO: Successfully added (jru) to the user database.
Add another user? (yes/no): no
Goodbye!
#

由於密碼在輸入時並不會顯示,在建立使用者帳號時要小心密碼不要輸入錯誤。

3.3.2.2. rmuser

要自系統完全移除一個使用者可使用超級使用者執行 rmuser(8)。這個指令會執行以下步驟:

  1. 移除使用者的 crontab(1) 項目,若項目存在。

  2. 移除任何屬於該使用者的 at(1) 工作。

  3. 中止所有該使用者擁有的程序。

  4. 自系統本地密碼檔移除該使用者。

  5. 選擇性移除該使用者的家目錄,若使用者擁有該目錄。

  6. /var/mail 移除屬於該使用者的收件郵件檔。

  7. 自暫存檔儲存區域 (如 /tmp) 移除所有使用者擁有的檔案。

  8. 最後,自 /etc/group 中該使用者所屬的所有群組移除該使用者。若群組無任何成員且群組名稱與該使用者名稱相同,則該群組也會一併移除。這是為了輔助

adduser(8) 替每位使用者建立獨一無二的群組。

rmuser(8) 無法用來移除超級使用者帳號,因為這幾乎代表著大規模破壞。

預設會使用互動式模式,如下範例所示。

例 3. rmuser 互動式帳號移除
# rmuser jru
Matching password entry:
jru:*:1001:1001::0:0:J. Random User:/home/jru:/usr/local/bin/zsh
Is this the entry you wish to remove? y
Remove user's home directory (/home/jru)? y
Removing user (jru): mailspool home passwd.
#

3.3.2.3. chpass

任何使用者都可以使用 chpass(1) 來變更自己的預設 Shell 以及與自己的使用者帳號關聯的個人資訊。超級使用者可以使用這個工具更改任何使用者的其他帳號資訊。

除了選填的使用者名稱外,未傳入任何選項時,chpass(1) 會開啟含有使用者資訊的編輯器。當使用者自編輯器離開,便會更新新的資訊到使用者資料庫。

離開編輯器時,此工具會提示使用者輸入密碼,除非使用超級使用者執行此工具。

以超級使用者的身份使用 chpass 中,超級使用者輸入了 chpass jru 並正在檢視這個使用者可以更改的欄位。若改以 jru 執行這個指令,只會顯示最後六個欄位供編輯,如 以一般使用者的身份使用 chpass 所示。

例 4. 以超級使用者的身份使用 chpass
#Changing user database information for jru.
Login: jru
Password: *
Uid [#]: 1001
Gid [# or name]: 1001
Change [month day year]:
Expire [month day year]:
Class:
Home directory: /home/jru
Shell: /usr/local/bin/zsh
Full Name: J. Random User
Office Location:
Office Phone:
Home Phone:
Other information:
例 5. 以一般使用者的身份使用 chpass
#Changing user database information for jru.
Shell: /usr/local/bin/zsh
Full Name: J. Random User
Office Location:
Office Phone:
Home Phone:
Other information:

指令 chfn(1) 以及 chsh(1) 皆連結至 chpass(1),就如同 ypchpass(1), ypchfn(1) 以及 ypchsh(1) 的關係。自從 NIS 支援自動化以後,便不再需要特別加上 yp,如何設定 NIS 在網路伺服器 中有說明。

3.3.2.4. passwd

任何使用者皆可簡單的使用 passwd(1) 更改自己的密碼。要避免意外或未授權的變更,這個指令在設定新密碼之前會提示使用者輸入原來的密碼:

例 6. 更改您的密碼
% passwd
Changing local password for jru.
Old password:
New password:
Retype new password:
passwd: updating the database...
passwd: done

超級使用者可以更改任何使用者的密碼透過在執行 passwd(1) 時指定使用者名稱。當此工具以超級使用者執行時,將不會提示輸入使用者目前的密碼,這可在使用者忘記原來的密碼時更改密碼。

例 7. 以超級使用者的身份更改其他使用者的密碼
# passwd jru
Changing local password for jru.
New password:
Retype new password:
passwd: updating the database...
passwd: done

如同 chpass(1)yppasswd(1) 連結到 passwd(1),因此 NIS 在兩個指令上皆可運作。

3.3.2.5. pw

pw(8) 工具可以建立、移除、修改以及顯示使用者與群組,它的功能是做為系統使用者與群組檔的前端。pw(8) 有非常強大的的指令列選項集,這讓該指令非常適合用於 Shell scripts,但新的使用者可能會發現它比其他在本節的指令要複雜許多。

3.3.3. 管理群組

群組代表一群使用者,群組可以由其群組名稱及 GID 來辨識。在 FreeBSD,核心會使用程序的 UID 以及其所屬的群組清單來決定程序可以做那些事。大多數情況使用者或程序的 GID 通常指的是清單中的第一個群組。

群組名稱與 GID 的對應表列在 /etc/group。這個純文字檔案使用了四個以冒號分隔的欄位,第一個欄位為群組名稱,第二個欄位為加密後的密碼,第二個欄位為 GID 以及第四個欄位為以逗號分隔的成員清單。要取得更完整的語法說明,請參考 group(5)

超級使用者可以使用文字編輯器修改 /etc/group,或者可使用 pw(8) 加入與編輯群組。例如,要加入一個叫做 teamtwo 的群組然後確認該群組已新增:

例 8. 使用 pw(8) 新增群組
# pw groupadd teamtwo
# pw groupshow teamtwo
teamtwo:*:1100:

在本例中,1100teamtwo 的 GID。目前 teamtwo 沒有任何成員,這個指令會加入 jru 作為 teamtwo 的成員。

例 9. 使用 pw(8) 加入使用者帳號到新的群組
# pw groupmod teamtwo -M jru
# pw groupshow teamtwo
teamtwo:*:1100:jru

-M 的參數是以逗號分隔的使用者清單,用來加入成員到新的 (空的) 群組或取代既有群組中的成員。對使用者來說這裡的群組成員與使用者列於密碼檔的主要群組不同 (額外的),這代表在 pw(8) 使用 groupshow 時不會顯示做為使用者主要群組的成員,但會顯示在使用 id(1) 或同類工具所查詢的資訊當中。當使用 pw(8) 來加入使用者到某個群組,該指令只會處理 /etc/group 且不會嘗試自 /etc/passwd 讀取其他的資料。

例 10. 使用 pw(8) 加入新成員到群組
# pw groupmod teamtwo -m db
# pw groupshow teamtwo
teamtwo:*:1100:jru,db

在本例當中,給 -m 的參數是以逗號分隔的使用者清單,用來加入使用者到群組。不像前面的例子,這些使用者會加入到群組,而非取代既有群組中的使用者。

例 11. 使用 id(1) 來查看所屬群組
% id jru
uid=1001(jru) gid=1001(jru) groups=1001(jru), 1100(teamtwo)

在本例中,jru 是群組 jru 以及 teamtwo 的成員。

要取得更多有關此指令的資訊及 /etc/group 的格式,請參考 pw(8) 以及 group(5)

3.4. 權限

在 FreeBSD 中,每個檔案與目都有相關聯的數個權限,且有許多工具可以檢視與修改這些權限。了解權限如何運作是必須的,這可確保使用者能夠存存取它們所需的檔案以及無法不正確的存取供作業系統或其他使用者擁有的檔案。

本節會探討在 FreeBSD 中所用到的傳統 UNIX™ 權限。要做檔案系統存取控制的微調,請參考 存取控制清單

在 UNIX™,基礎權限透過三種類型的存取來分配:讀取、寫入與執行。這些存取類型用來決定檔案擁有者、群組以及其他人 (其他任何人) 的檔案存取權。讀取、寫入及執行權限可使用 r, w, and x 字母來表示。這些權限也可以使用二進位數字來表示每種權限的開或關 (0)。當以二進位數字來表示時,閱讀的順序為 rwx,其中 r 開啟的值為 4w 開啟的值為 2 以及 x 開啟的值為 1

表格 4.1 摘要了可用的數字及可用的字母。當閱讀 "目錄清單標示" 欄位時,- 用來代表該權限設為關閉。

表 2. UNIX™ 權限
數值權限目錄清單標示

0

不可讀取, 不可寫入, 不可執行

---

1

不可讀取, 不可寫入, 可執行

--x

2

不可讀取, 可寫入, 不可執行

-w-

3

不可讀取, 可寫入, 可執行

-wx

4

可讀取, 不可寫入, 不可執行

r--

5

可讀取, 不可寫入, 可執行

r-x

6

可讀取, 可寫入, 不可執行

rw-

7

可讀取, 可寫入, 可執行

rwx

使用 ls(1) 指令時,可以加上 -l 參數, 來檢視詳細的目錄清單。 清單中欄位的資訊包含檔案對所有者、群組及其他人的權限。 在任一個目錄底下執行 ls -l,會顯示如下的結果:

% ls -l
total 530
-rw-r--r--  1 root  wheel     512 Sep  5 12:31 myfile
-rw-r--r--  1 root  wheel     512 Sep  5 12:31 otherfile
-rw-r--r--  1 root  wheel    7680 Sep  5 12:31 email.txt

第一個 (最左邊) 的字元用來表示這個檔案的類型為何,除標準檔案以外,尚有目錄、特殊字元裝置、Socket 及其他特殊虛擬檔案裝置, 在此例當中,- 表示該檔案為一個標準的檔案。 範例中接下來的三個字元中,rw- 代表所有者對檔案擁有的權限。 再接下來的三個字元, r-- 則代表群組對檔案擁有的權限, 最後三個字元,r-- 則代表其他人對檔案擁有的權限。 破折號 (-) 表示沒有權限,範例中的這個檔案的權限, 只允許所有者讀取、寫入檔案,群組以及其他人僅能讀取檔案。 根據以上的表格,此種權限的檔案可以使用 644 來表示, 每組數字分別代表檔案的三種權限。

那系統如何控制裝置的權限? 實際上 FreeBSD 對大多的硬碟裝置就如同檔案,程式可以開啟、讀取以及寫入資料如一般檔案。 這些特殊裝置檔案都儲存於 /dev/ 目錄中。

目錄也同如檔案,擁有讀取、寫入及執行的權限, 但在執行權限上與檔案有明顯的差異。 當目錄被標示為可執行時,代表可以使用 cd(1) 指令切換進入該目錄。 也代表能夠存取在此目錄之中的已知檔名的檔案,但仍會受限於檔案本身所設定的權限。

要能夠列出目錄內容,必須擁有目錄的讀取權限。 要刪除已知檔名的檔案,必須擁有檔案所在目錄的寫入 以及 執行的權限。

還有一些權限位元,但這些權限主要在特殊情況使用,如 setuid 執行檔及 sticky 目錄。 如果您還想知道更多檔案權限的資訊及使用方法,請務必參閱 chmod(1)

3.4.1. 權限符號

權限符號可稱做符號表示,使用字元的方式來取代使用數值來設定檔案或目錄的權限。 符號表示的格式依序為 (某人)(動作)(權限),可使用的符號如下:

項目字母代表意義

(某人)

u

使用者

(某人)

g

群組所有者

(某人)

o

其他

(某人)

a

全部 ("world")

(動作)

+

增加權限

(動作)

-

移除權限

(動作)

=

指定權限

(權限)

r

讀取

(權限)

w

寫入

(權限)

x

執行

(權限)

t

Sticky 位元

(權限)

s

設定 UID 或 GID

如先前同樣使用 chmod(1) 指令來設定,但使用的參數為這些字元。 例如,您可以使用下列指令禁止其他使用者存取檔案 FILE

% chmod go= FILE

若有兩個以上的權限更改可以使用逗號 (,) 區隔。 例如,下列指令將會移除群組及全部人 ("world") 對檔案 FILE 的寫入權限, 並使全部人對該檔有執行權限:

% chmod go-w,a+x FILE

3.4.2. FreeBSD 檔案旗標

除了前面提到的檔案權限外,FreeBSD 支援使用 "檔案旗標"。 這些旗標增加了檔案的安全性及管理性,但不包含目錄。有了檔案旗標可確保在某些時候 root 不會意外將檔案修改或移除。

修改的檔案 flag 僅需要使用擁有簡易的介面的 chflags(1) 工具。 例如,標示系統禁止刪除的旗標於檔案 file1,使用下列指令:

# chflags sunlink file1

若要移除系統禁止刪除的旗標,只需要簡單在 sunlink 前加上 "no",例如:

# chflags nosunlink file1

使用 ls(1) 及參數 -lo 可檢視檔案目前的旗標:

# ls -lo file1
-rw-r--r--  1 trhodes  trhodes  sunlnk 0 Mar  1 05:54 file1

多數的旗標僅能由 root 使用者來標示或移除,而部份旗標可由檔案所有者設定。 我們建議系統管理者可閱讀 chflags(1)chflags(2) 說明以瞭解相關細節。

3.4.3. setuidsetgidsticky 權限

除了已經探討過的權限外,這裡尚有另外三種特別的設定所有管理者都應該知道,這些設定為 setuid, setgid 以及 sticky 權限。

這些設定對某些一般不會授權給一般使用者的 UNIX™ 操作非常重要,它讓這些功能可運作。要了解這些權限,就必須說明真實使用者 ID (Real user ID) 與有效使用者 ID (Effective user ID) 的差異。

真實使用者 ID 即是擁有者或啟動程序者的 UID,而有效 UID 是執行程序所使用的使用者 ID。例如,passwd(1) 在使用者更改自己的密碼時會以真實使用者 ID 執行,然而,為了要更新密碼資料庫,該指令必須以 root 使用者做為有效 ID 來執行,這讓使用者可以更改自己的密碼而不會遇到權限不足 (Permission Denied) 的錯誤。

setuid 權限可以透過在權限集前加上數字 (4) 來設定,如下範例所示:

# chmod 4755 suidexample.sh

現在 suidexample.sh 的權限會如下所示:

-rwsr-xr-x   1 trhodes  trhodes    63 Aug 29 06:36 suidexample.sh

注意,s 現在取代了原來的執行位元成為指定檔案擁有者權限集的一部份,這會允許須要提升權限的工具,如 passwd(1) 可正常使用。

mount(8)nosuid 選項會造成這類 Binary 執行失敗,但不會警告使用者。由於 nosuid Wrapper 可能可繞過該選項,因此該選項並非完全可靠。

實際來看這個範例,先開啟兩個終端機,其中一個用一般使用者輸入 passwd。在等待輸入新密碼的同時,檢查程序表並查看 passwd(1) 程序的使用者資訊:

於終端機 A:

Changing local password for trhodes
Old Password:

於終端機 B:

# ps aux | grep passwd
trhodes  5232  0.0  0.2  3420  1608   0  R+    2:10AM   0:00.00 grep passwd
root     5211  0.0  0.2  3620  1724   2  I+    2:09AM   0:00.01 passwd

雖然使用一般使用者來執行 passwd(1),但該程序使用了 root 的有效 UID。

setgid 權限的功能與 setuid 相似,當應用程式或工具使用此設定執行時,將會以擁有該檔案的群組來執行,而非執行行該程序的使用者。

要在檔案設定 setgid 權限,需在 chmod(1) 的參數前加上 (2):

# chmod 2755 sgidexample.sh

注意以下清單中,s 現在位於指定群組權限設定的欄位:

-rwxr-sr-x   1 trhodes  trhodes    44 Aug 31 01:49 sgidexample.sh

在以上這些範例中,雖然在例子中的 Shell script 是可執行的檔案,但並不會以其他的 EUID 或有效使用者 ID 執行,這是因為 Shell script 並不會存取 setuid(2) 系統呼叫 (System call)。

setuidsetgid 權限位元可能會因允許提升權限而降低系統的安全性,因此有了第三個特殊的權限:sticky bit,可以加強系統的安全性。

當在目錄上設定 sticky bit,將只允許由檔案擁有者刪除檔案。這對避免公開目錄,如 /tmp 中的檔案被不擁有該檔案的人刪除非常有用。要使用這個權限,可在權限集前加上 (1):

# chmod 1777 /tmp

sticky bit 權限會以 t 顯示於權限集的最後:

# ls -al / | grep tmp
drwxrwxrwt  10 root  wheel         512 Aug 31 01:49 tmp

3.5. 目錄結構

認識 FreeBSD 的目錄架構,就可對系統有概略的基礎理解。 最重要的莫過於整個目錄的根目錄,就是 "/" 目錄, 該目錄會在開機時最先掛載 (mount),裡面會有開機所會用到必備檔案。 此外,根目錄還有紀錄其他檔案系統的掛載點相關設定。

「掛載點」就是讓新增的檔案系統,能接到上層的檔案系統 (通常就是「根目錄」檔案系統) 的目錄。 在 磁碟組織 這邊對此有更詳細介紹。 標準的掛載點包括了 /usr/, /var/, /tmp/, /mnt/ 以及 /cdrom/。 這些目錄通常會記錄在 /etc/fstab 設定檔內。 /etc/fstab 是記錄各檔案系統及相關掛載點的表格。 大部分在 /etc/fstab 有記錄的檔案系統,會在開機時由 rc(8) Script 來自動掛載,除非它們有設定 noauto 選項。 其中細節說明可參閱 fstab

有關檔案系統架構的完整說明可參閱 hier(7)。 現在呢,讓我們大致先一窺常見的目錄有哪些吧。

目錄說明

/

檔案系統的根目錄。

/bin/

單使用者 (Single-user)、多使用者 (Multi-user) 兩種模式皆可使用的基本工具 。

/boot/

作業系統開機過程會用到的程式、設定檔。

/boot/defaults/

預設的開機啟動設定檔,詳情請參閱 loader.conf(5)

/dev/

裝置節點 (Device node),詳情請參閱 intro(4)

/etc/

系統設定檔及一些 Script 檔。

/etc/defaults/

預設的系統設定檔,詳情請參閱 rc(8)

/etc/mail/

郵件傳輸代理程式,像是 sendmail(8) 的相關設定檔。

/etc/periodic/

每日、每週、每月透過 cron(8),執行的定期排程 Script,詳情請參閱 periodic(8)

/etc/ppp/

ppp(8) 設定檔。

/mnt/

系統管理者慣用充當臨時掛載點的空目錄。

/proc/

程序 (Process) 檔案系統,詳情請參閱 procfs(5)mount_procfs(8)

/rescue/

緊急救援用途的一些靜態連結 (Statically linked) 的程式,詳情請參閱 rescue(8)

/root/

root 帳號的家目錄。

/sbin/

供單使用者 (Single-user) 及多使用者 (Multi-user) 環境使用的系統程式及管理工具 。

/tmp/

臨時檔案。 一般而言,重開機之後 /tmp 內的東西會被清除掉。 而通常會將以記憶體為基礎 (Memory-based) 的檔案系統掛載在 /tmp 上。 這些瑣事可透過 tmpmfs 相關的 rc.conf(5) 環境變數來自動完成 。(或是在 /etc/fstab 內做設定, 詳情請參閱 mdmfs(8))。

/usr/

主要是使用者所安裝的工具程式、應用程式存放處。

/usr/bin/

常用工具、開發工具、應用軟體。

/usr/include/

標準 C include 檔案。

/usr/lib/

程式庫存放處。

/usr/libdata/

其他各式工具的資料檔。

/usr/libexec/

系統 Daemon 及系統工具程式 (透過其他程式來執行)。

/usr/local/

存放一些自行安裝的執行檔、程式庫等等。 同時,也是 FreeBSD Port 架構的預設安裝目錄。 /usr/local 內的目錄架構大致與 /usr 相同,詳情請參閱 hier(7) 說明。 但 man 目錄例外,它們是直接放在 /usr/local 底下,而非 /usr/local/share,而 Port 所安裝的說明文件則在 share/doc/port

/usr/obj/

在編譯 /usr/src 目錄時所產生的相關架構目地檔。

/usr/ports/

FreeBSD Port 套件集 (選用)。

/usr/sbin/

由使用者執行的系統 Daemon 及系統工具。

/usr/shared/

各架構皆共通的檔案。

/usr/src/

BSD 原始碼 (或自行新增的)。

/var/

存放各種用途的日誌 (Log) 檔、臨時或暫時存放、列印或郵件的緩衝 (Spool) 檔案。有時候,以記憶體為基礎 (Memory-based) 的檔案系統也會掛載在 /var。 這些瑣事可透過 varmfs 相關的 rc.conf(5) 環境變數來自動完成。(或是在 /etc/fstab 內做設定,相關細節請參閱 mdmfs(8))。

/var/log/

各項系統記錄的日誌 (Log) 檔。

/var/mail/

各使用者的郵件 (Mailbox) 檔案。

/var/spool/

各種印表機、郵件系統的緩衝 (Spool) 目錄。

/var/tmp/

臨時檔案。 這些檔案在重開機後通常仍會保留,除非 /var 是屬於以記憶體為基礎 (Memory-based) 的檔案系統。

/var/yp/

NIS 對應表。

3.6. 磁碟組織

FreeBSD 用來尋找檔案的最小單位就是檔案的名稱了。 檔案的名稱有大小寫之分,所以說 readme.txtREADME.TXT 是兩個不同的檔案。 FreeBSD 並不使用副檔名 (.txt) 來判別這是一個程式檔、文件檔或是其他類型的檔案。

檔案存在目錄裡面。 一個目錄中可能沒有任何檔案,也可能有好幾百個檔案。 目錄之中也可以包含其他的目錄; 您可以建立階層式的目錄以便資料的管理。

檔案或目錄的對應是藉由給定的檔案或目錄名稱,然後加上正斜線符號 (/);之後再視需要加上其他的目錄名稱。 如果您有一個目錄 foo ,裡面有一個目錄叫作 bar,這個目錄中又包含了一個叫 readme.txt 的檔案,那麼這個檔案的全名,或者說檔案的路徑 (Path)就是 foo/bar/readme.txt。注意這與 Windows™ 用來分隔檔案與目錄名稱所使用的 \ 不同,且 FreeBSD 在路徑上並不使用磁碟機代號或其他磁碟機名稱,意思是,在 FreeBSD 上不會有人輸入 c:\foo\bar\readme.txt 這種路徑。

目錄及檔案儲存在檔案系統 (File system) 之中。 每個檔案系統都有唯一一個最上層的目錄,叫做根目錄 (Root directory)。 然後在這個根目錄下面才能有其他的目錄。其中一個檔案系統會被指定成為根檔案系統 (Root file system)/,其他的檔案系統均會掛載 (Mount) 在該根檔案系統之下,不論在 FreeBSD 有多少個磁碟,所有目錄都會成為該磁碟的一部份。

假設您有三個檔案系統,分別叫作 A, BC。 每個檔案系統都包含兩個目錄,叫做 A1, A2 (以此類推得 B1, B2C1, C2)。

A 為主要的檔案系統;如果您用 ls(1) 指令查看此目錄的內容,您會看到兩個子目錄: A1A2,如下所示:

example dir1

一個檔案系統必須以目錄形式掛載於另一個檔案系統上。 因此,假設您將 B 掛載於 A1 之上,則 B 的根目錄就變成了 A1,而在 B 之下的任何目錄的路徑也隨之改變:

example dir2

B1B2 目錄中的任何檔案必須經由路徑 /A1/B1/A1/B2 才能達到。 所有原來在 /A1 中的檔案會暫時被隱藏起來,直到 B卸載 (Unmount) 後才會再顯現出來。

如果 B 掛載在 A2 之上,則會變成:

example dir3

上面的路徑分別為 /A2/B1/A2/B2

檔案系統可以掛在其他檔案系統的目錄之上。 延續之前的例子,C 檔案系統可以掛在檔案系統 BB1 目錄之上,如圖所示:

example dir4

或者 C 直接掛載於 AA1 目錄之上:

example dir5

您可以使用單一的一個大的根檔案系統而不建立其他的檔案系統。 這樣有好處也有有壞處。

使用多個檔案系統的好處
  • 不同的檔案系統在掛上的時候可以有不同的 掛載參數 (Mount option)。 舉例來說,為求謹慎您可以將根檔案系統設成唯讀, 以避免不小心刪除或修改掉重要的檔案。 將使用者可寫入的檔案系統 (例如 /home) 獨立出來也可以讓他們用 nosuid 的參數掛載,此選項可以讓在這個檔案系統中執行檔的 suid/guid 位元失效,可讓系統更安全。

  • FreeBSD 會自動根據您檔案系統的使用方式來做最佳的檔案配置方式。 因此,一個有很多小檔案、 常常寫入的檔案系統跟只有幾個較大的檔案的檔案系統配置是不一樣的。 如果您只有單一個大的檔案系統,這部分就沒用了。

  • FreeBSD 的檔案系統在停電的時候很穩固。 然而,在某些重要的時候停電仍然會對檔案系統結構造成損害。 分割成許多個檔案系統的話在系統在停電後比較能夠正常啟動, 以便您在需要的時候將備份資料回存回來。

使用單一檔案系統的好處
  • 檔案系統的大小是固定的。 若您在當初安裝 FreeBSD 的時指定了一個大小,可是後來您想把空間加大,在沒有備份的情況下很難達成,您必須將檔案系統重新建立為您需要的大小,然後將備份回存回來。

    FreeBSD 的 growfs(8) 指令可以突破此限制直接變更檔案系統的大小。

檔案系統放在分區 (Partition) 中。 因為 FreeBSD 承襲 UNIX™ 架構,這邊講的分區和一般提到的分割區 (例如 MS-DOS™ 分割區) 不同。每一個分區由一個代號 (字母) 表示,從 ah。 每個分區只能含有一個檔案系統,因此在表示檔案系統時,除了用該檔案系統的常用的掛載點表示外,也可以使用該檔案系統所在的分區來表示。

FreeBSD 也會使用磁碟空間作為交換空間 (Swap space) 來提供虛擬記憶體 (Virtual memory)。 這讓您的電腦好像擁有比實際更多的記憶體。 當 FreeBSD 的記憶體用完的時候,它會把一些目前沒用到的資料移到交換空間,然後在用到的時候移回去 (同時移出部份沒用到的)。

有些分割區有特定的使用慣例。

分區慣例

a

通常含有根檔案系統。

b

通常含有交換空間。

c

通常用來代表整個切割區 (Slice),因此大小會與其所在的切割區一樣。這可讓需要對整個切割區處理的工具 (例如硬碟壞軌檢查工具) 可在 c 分區上執行。一般來說不會把檔案系統建立在這個分區。

d

分區 d 曾經有代表特殊意義,但是已經不再使用。所以現在 d 和一般的分區相同。

在 FreeBSD 的磁碟會分割成數個切割區 (Slice),如同 Windows™ 中由編號 1 到 4 表示的分割區。這些切割區會再分成數個分區,每個分區內含檔案系統,且會使用字母來標示。

切割區的編號在裝置名稱後面,會先以 s 為字首,然後從 1 開始編號。 因此 "da0s1" 是指第一個 SCSI 硬碟的第一個切割區。 一個磁碟上只能有四個實體切割區,但是在實體切割區中放進適當類型的邏輯切割區。這些延伸的切割區編號會從 5 開始,所以 "ada0s5" 是第一個 SATA 硬碟上的第一個延伸切割區。因此可以預期這些由檔案系統使用的裝置 (Device) 上均會各別佔據一個切割區。

切割區、"危險專用 (Dangerously dedicated)" 的實體磁碟機以及其他內含分割區 (Partition) 的磁碟都是以字母 ah 來表示。 字母會接在裝置名稱的後面,因此 "da0a" 是第一顆 "dangerously dedicated" 磁碟機 da 上的 a 分割區。 而 "ada1s3e" 則是第二顆 SATA 硬碟上第三個切割區的第五個分區。

終於,我們可以辨識系統上的每個磁碟了,一個磁碟的名稱會有一個代碼來表示這個磁碟的類型,接著是一個表示這是那一個磁碟的編號。不像切割區,磁碟的編號從 0 開始。常見的代碼可以參考 磁碟裝置名稱

當要參照一個分區的時候,需包含磁碟機名稱、s、切割區編號以及分區字母。範例可以參考 磁碟、切割區及分區命名範例

磁碟的概念模型 示範了一個基本的磁碟配置,相信對您有些幫助。

要安裝 FreeBSD,您必須先建置磁碟的切割區,接著於切割區中建立要給 FreeBSD 用的分區。 最後在這些分區中建立檔案系統 (或交換空間) 並決定要將這些檔案系統掛載於哪裡。

表 3. 磁碟裝置名稱
磁碟機類型磁碟機裝置稱

SATA 及 IDE 硬碟

adaad

SCSI 硬碟與 USB 儲存裝置

da

SATA 與 IDECD-ROM 光碟機

cdacd

SCSICD-ROM 光碟機

cd

軟碟機

fd

各種非標準 CD-ROM 光碟機

mcd 代表 Mitsumi CD-ROM 以及 scd 代表 Sony CD-ROM 光碟機

SCSI 磁帶機

sa

IDE 磁帶機

ast

RAID 磁碟機

範例包含 aacd 代表 Adaptec™ AdvancedRAID,mlxdmlyd 代表 Mylex™,amrd 代表 AMI MegaRAID™,idad 代表 Compaq Smart RAID,twed 代表 3ware™ RAID.

例 12. 磁碟、切割區及分區命名範例
名稱意義

ada0s1a

第一個 SATA 硬碟 (ada0) 上第一個切割區 (s1)的第一個分區(a) 。

da1s2e

第二個 SCSI 硬碟 (da1) 上第二個切割區 (s2) 的第五個分區 (e) 。

例 13. 磁碟的概念模型

此圖顯示 FreeBSD 中連接到系統的第一個 SATA 磁碟機內部配置圖。 假設這個磁碟的容量是 250 GB,並且包含了一個 80 GB 的切割區及一個 170 GB 的切割區 (MS-DOS™ 的分割區)。 第一個切割區是 Windows™NTFS 檔案系統的 C: 磁碟機,第二個則安裝了 FreeBSD。 本範例中安裝的 FreeBSD 有四個資料分區及一個交換分區。

這四個分區中各有一個檔案系統。 分區 a 是根檔案系統、分區 d/var/、分區 e/tmp/,而分區 f/usr/。分區字母 c 用來代表整個切割區,因此並不作為一般分區使用。

disk layout

3.7. 掛載與卸載檔案系統

檔案系統就像一顆樹。/ 就像是樹根,而 /dev/usr 以及其他在根目錄下的目錄就像是樹枝,而這些樹枝上面又還有分支,像是 /usr/local 等。

因為某些原因,我們會將一些目錄分別放在不同的檔案系統上。 如 /var 包含了可能會滿出來的 log/spool/ 等目錄以及各式各樣的暫存檔。 把根檔案系統塞到滿出來顯然不是個好主意,所以我們往往會比較傾向把 /var/ 中拉出來。

另一個常見到把某些目錄放在不同檔案系統上的理由是: 這些檔案在不同的實體或虛擬磁碟機上。 像是網路檔案系統 (Network File System) 詳情可參考 網路檔案系統 (NFS) 或是光碟機。

3.7.1. fstab

/etc/fstab 裡面有設定的檔案系統會在開機 (FreeBSD 開機程序) 的過程中自動地被掛載 (除非該檔案系統有被加上 noauto 參數)。檔案內容的格式如下:

device       /mount-point fstype     options      dumpfreq     passno
device

已存在的裝置名稱,詳情請參閱 磁碟裝置名稱

mount-point

檔案系統要掛載到的目錄 (該目錄必須存在)。

fstype

檔案系統類型,這是要傳給 mount(8) 的參數。 FreeBSD 預設的檔案系統是 ufs

options

可讀可寫 (Read-Write) 的檔案系統用 rw,而唯讀 (Read-Only) 的檔案系統則是用 ro,後面視需要還可以加其他選項。 常見的選項如 noauto 是用在不要於開機過程中自動的掛載的檔案系統。 其他選項可參閱 mount(8) 說明。

dumpfreq

dump(8) 由此項目決定那些檔案系統需要傾印。 如果這格空白則以零為預設值。

passno

這個項目決定檔案系統檢查的順序。 對於要跳過檢查的檔案系統,它們的 passno 值要設為零。 根檔案系統的 passno 值應設為一 (因為需要比所有其他的還要先檢查),而其他的檔案系統的 passno 值應該要設得比一大。 若有多個檔案系統具有相同的 passno 值,則 fsck(8) 會試著平行地 (如果可能的話) 檢查這些檔案系統。

更多關於 /etc/fstab 檔案格式及選項的資訊請參閱 fstab(5) 說明文件。

3.7.2. 使用 mount(8)

mount(8) 指令是拿來掛載檔案系統用的。基本的操作指令格式如下:

# mount device mountpoint

mount(8) 裡面有提到一大堆的選項,不過最常用的就是這些:

掛載選項
-a

把 /etc/fstab 裡面所有還沒有被掛載、沒有被標記成 /etc/fstab 而且沒有用 -t 排除的檔案系統掛載起來。

-d

執行所有的動作,但是不真的去呼叫掛載的系統呼叫 (System call)。 這個選項和 -v 搭配拿來推測 mount(8) 將要做什麼動作時很好用。

-f

強迫掛載不乾淨的檔案系統 (危險),或是用來強制取消寫入權限 (把檔案系統的掛載狀態從可存取變成唯讀)。

-r

用唯讀的方式掛載檔案系統。 這個選項和在 -o 選項中指定 ro 參數是一樣的。

-t fstype

用指定的檔案系統型態來掛載指定的檔案系統,或是在有 -a 選項時只掛載指定型態的檔案系統。預設的檔案系統類型為 "ufs"。

-u

更新檔案系統的掛載選項。

-v

顯示詳細資訊。

-w

以可讀寫的模式掛載檔案系統。

-o 選項後面會接著以逗號分隔的參數:

nosuid

不解析檔案系統上的 setuid 或 setgid 旗標, 這也是一個蠻有用的安全選項。

3.7.3. 使用 umount(8)

要卸載檔案系統可使用 umount(8) 指令。該指令需要一個參數可以是掛載點 (mountpoint),裝置名稱,以及 -a 或是 -A 等選項。

加上 -f 可以強制卸載,加上 -v 則是會顯示詳細資訊。 要注意的是一般來說用 -f 並不是個好主意,強制卸載檔案系統有可能會造成電腦當機, 或者損壞檔案系統內的資料。

-a-A 是用來卸載所有已掛載的檔案系統,另外還可以用 -t 來指定要卸載的是哪些種類的檔案系統。 要注意的是 -A 並不會試圖卸載根檔案系統。

3.8. 程序與 Daemon

FreeBSD 是一個多工的作業系統,也就是說在同一時間內可以跑超過一個程式。 每一個正在花時間跑的程式就叫做程序 (Process)。 您下的每個指令都至少會開啟一個新的程序, 而有些系統程序是一直在跑以維持系統正常運作的。

每一個程序都有一個獨一無二的數字叫做 程序代號 (Process ID, PID),而且就像檔案一樣,每一個程序也有擁有者及群組。 擁有者及群組的資訊是用來決定什麼檔案或裝置是這個程序可以開啟的 (前面有提到過檔案權限)。 大部份的程序都有父程序。 父程序是開啟這個程序的程序,例如:您對 Shell 輸入指令,Shell 本身就是一個程序,而您執行的指令也是程序。 每一個您用這種方式跑的程序的父程序都是 Shell。 有一個特別的程序叫做 init(8) 是個例外,在 FreeBSD 開機的時候 init 會自動地被開啟,init 永遠是第一個程序,所以他的 PID 一直都會是 1

有些程式並不是設計成一直在接收使用者的輸入的, 而是在開始執行的時候就從中斷與終端機的連線。 例如說, 網頁伺服器整天都在回應網頁方面的要求,它通常不需要您輸入任何東西。 另外,像是把信從一個站傳送到另一個站的程式,也是這種類型的應用程式。我們把這種程式稱作 Daemon。 Daemon 一詞是來自是希臘神話中的角色:祂們既不屬於善良陣營或邪惡陣營,祂們在背地裡做一些有用的事情。這也就是為何 BSD 的吉祥物,是一隻穿著帆布鞋拿著三叉耙的快樂小惡魔的原因。

通常來說做為 Deamon 執行的程式名字後面都會加一個字母 "d"。 BIND 是 Berkeley Internet Name Domain 的縮寫,但實際上執行的程式名稱是 named、Apache 網頁伺服器的程式名稱是 httpd、行列式印表機緩衝服務 (Line Printer Spooling) Daemon 是 lpd,依此類推。 但這是習慣用法,並沒有硬性規定,例如 Sendmail 主要的寄信 Daemon 是叫做 sendmail 而不是 maild

3.8.1. 檢視程序

要看系統執行中的程序,有兩個相當有用的指令可用: ps(1) 以及 top(1)ps(1) 指令是用來列出正在執行之程序,而且可以顯示它們的 PID、用了多少記憶體、執行的指令名稱及其後之參數是什麼等等。 top(1) 指令則是顯示所有正在執行的程序, 並且數秒鐘更新一次。因此您可以互動式的觀看您的電腦正在做什麼。

在預設的情況下,ps(1) 指令只會顯示使用者所擁有的的程序。 例如:

% ps
 PID TT  STAT    TIME COMMAND
8203  0  Ss   0:00.59 /bin/csh
8895  0  R+   0:00.00 ps

在這個範例裡可以看到 ps(1) 的輸出分成好幾個欄位。 PID 就是前面有提到的程序代號。 PID 的分配是從 1 開始一直到 99999,如果用完的話又會繞回來重頭開始分配 (若該 PID 已經在用了,則 PID 不會重新分配)。 TT 欄位是指這個程式在哪個 Console (tty) 上執行,在這裡可以先忽略不管。STAT 是程式的狀態,也可以先不要管。TIME 是這個程式在 CPU 上執行的時間—​這通常不是程式總共花的時間, 因為當您開始執行程式後,大部份的程式在 CPU 上執行前會先花上不少時間等待 。 最後,COMMAND 是執行這個程式的指令。

有幾個不同的選項組合可以用來變更顯示出來的資訊,其中一個最有用的組合是 auxwwa 可以顯示所有正在跑的程序的指令,不只是您自已的。 u 則是顯示程序的擁有者名稱以及記憶體使用情況。 x 可以把 daemon 程序顯示出來, 而 ww 可讓 ps(1) 顯示出每個程序完整的內容, 而不致因過長而被螢幕截掉了。

top(1) 也有類似的輸出。 一般的情況看像是這樣:

% top
last pid:  9609;  load averages:  0.56,  0.45,  0.36              up 0+00:20:03  10:21:46
107 processes: 2 running, 104 sleeping, 1 zombie
CPU:  6.2% user,  0.1% nice,  8.2% system,  0.4% interrupt, 85.1% idle
Mem: 541M Active, 450M Inact, 1333M Wired, 4064K Cache, 1498M Free
ARC: 992M Total, 377M MFU, 589M MRU, 250K Anon, 5280K Header, 21M Other
Swap: 2048M Total, 2048M Free

  PID USERNAME    THR PRI NICE   SIZE    RES STATE   C   TIME   WCPU COMMAND
  557 root          1 -21  r31   136M 42296K select  0   2:20  9.96% Xorg
 8198 dru           2  52    0   449M 82736K select  3   0:08  5.96% kdeinit4
 8311 dru          27  30    0  1150M   187M uwait   1   1:37  0.98% firefox
  431 root          1  20    0 14268K  1728K select  0   0:06  0.98% moused
 9551 dru           1  21    0 16600K  2660K CPU3    3   0:01  0.98% top
 2357 dru           4  37    0   718M   141M select  0   0:21  0.00% kdeinit4
 8705 dru           4  35    0   480M    98M select  2   0:20  0.00% kdeinit4
 8076 dru           6  20    0   552M   113M uwait   0   0:12  0.00% soffice.bin
 2623 root          1  30   10 12088K  1636K select  3   0:09  0.00% powerd
 2338 dru           1  20    0   440M 84532K select  1   0:06  0.00% kwin
 1427 dru           5  22    0   605M 86412K select  1   0:05  0.00% kdeinit4

輸出的資訊分成兩個部份。開頭 (前五行或六行) 顯示出最近一個程序的 PID、系統平均負載 (系統忙磁程度評估方式)、系統的開機時間 (自上次重新開機) 以及現在的時間等。 在開頭裡面的其他數字分別是在講有多少程序正在執行、有多少記憶體及交換空間被占用了,還有就是系統分別花了多少時間在不同的 CPU 狀態上。若有載入 ZFS 檔案系統模組,會有一行 ARC 標示有多少資料從磁碟改由記憶體快取中取得。

接下來的部份是由好幾個欄位所構成,和 ps(1) 輸出的資訊類似。 就如同前例,您可以看到 PID、使用者名稱、CPU 花費的時間以及正在執行的指令。 top(1) 在預設的情況下還會告訴您程序用掉了多少的記憶體空間。 在這邊會分成兩欄,一個是總用量 (Total size),另一個是實際用量 (Resident size)----總用量是指這個應用程式需要的記憶體空間,而實際用量則是指目前實際上該程式的記憶體使用量。

top(1) 每隔 2 秒鐘會自動更新顯示內容,可用 -s 選項來改變間隔的時間。

3.8.2. 終止程序

要與執行中的程序或 Daemon 溝通唯一的方法是透過 kill(1) 指令傳送信號 (Signal)。 信號有很多種,有些有特定的意義,有些則是會由應用程式來解讀,應用程式的說明文件會告訴您該程式是如何解讀信號。 使用者只能送信號給自己所擁有的程序,送信號給其他人的程序會出現權限不足的錯誤。 唯一的例外是 root使用者,他可以送信號給任何人的程序。

作業系統在某些情況也會送信號給應用程式。 假設有個應用程式寫得不好,企圖要存取它不該碰的記憶體的時候,FreeBSD 會送一個 "Segmentation Violation" 信號 (SIGSEGV) 給這個程序。 如果有一個應用程式用了 alarm(3) 的系統呼叫 (System call) 要求系統在過一段時間之後發出通知,時間到了的時候系統就會發出"通知"信號 (SIGALRM) 給該程式。

SIGTERMSIGKILL 這兩個信號可以拿來終止程序。 用 SIGTERM 結束程序是比較有禮貌的方式,該程序收到信號後可以把自已所使用的日誌檔關閉及其他要在結束前要做的事完成, 然後在關掉程序之前結束掉手邊的工作。 在某些情況下程序有可能會忽略 SIGTERM,如它正在做一些不能中斷的工作的話。

SIGKILL 就沒有辦法被程序忽略。 傳送 SIGKILL 信號給程序通常會將程序直接中止。

其他常用的信號有:SIGHUP, SIGUSR1SIGUSR2。 這些是通用的信號,對不同的應用程式會有不同的反應。

舉例來說,當您更動了網頁伺服器的設定檔,您想要叫網頁伺服器去重新讀取設定。 重新啟動 httpd 會造成網頁伺服器暫停服務一段時間,我們可以傳送 SIGHUP 信號來取代關掉重開。 不同的 Daemon 會有不同的行為,所以使用前請先參考 Deamon 的說明文件查看是否可以達到想要的結果。

Procedure: 送信號給程序

這個範例將會示範如何送一個信號給 inetd(8)inetd(8) 的設定檔是 /etc/inetd.conf,而 inetd(8) 會在收到 SIGHUP 的時候重新讀取這個設定檔。

  1. 使用 pgrep(1) 來查詢要傳送信號的目標程序。 在這個例子中 inetd(8) 的 PID 為 198:

    % pgrep -l inetd
    198  inetd -wW
  2. 使用 kill(1) 來發送信號。因為 inetd(8)root 所有,因此必須先用 su(1) 切換成 root 先。

    % su
    Password:
    # /bin/kill -s HUP 198

    對大多數 UNIX™ 指令來講,kill(1) 執行成功時並不會輸出任何訊息。 假設您送一個信號給某個不是使用者所擁有的程序, 那麼就會顯示這個錯誤訊息: kill: PID: Operation not permitted。 若打錯 PID 的話,那就會把信號送給錯誤的程序,並把該程序關閉,或者是把信號送給一個非使用中的 PID,那您就會看到錯誤:kill: PID: No such process

    為何要使用 /bin/kill

    多數 Shell 都有提供內建的 kill 指令。 也就是說這種 shell 會直接發送信號,而不是執行 /bin/kill。 但要小心不同的 shell 會有不同的語法來指定信號的名稱等。 與其嘗試去把它們通通學會,不如就單純的直接用 /bin/kill

要送其他的信號的話也是非常類似,就視需要把指令中的 TERMKILL 替換成其他信號的名稱即可。

隨便抓一個系統中的程序然後把他砍掉並不是個好主意。 特別是 init(8), PID 1 是一個非常特別的程序。 執行 /bin/kill -s KILL 1 的結果就是系統立刻關機。 因此在您按下 Return 要執行 kill(1) 之前, 請一定要記得再次確認您下的參數。

3.9. Shell

Shell 提供了指令列介面可用來與作業系統互動,Shell 負責從輸入的頻道接收指令並執行它們。 多數 Shell 也內建一些有助於日常工作的功能,像是檔案管理、檔案搜尋、指令列編輯、指令巨集以及環境變數等。 FreeBSD 有內附了幾個 Shell,包含 Bourne Shell (sh(1)),與改良版的 C-shell (tcsh(1))。 還有許多其他的 Shell 可以從 FreeBSD Port 套件集中取得,像是 zsh 以及 bash 等。

要用哪個 Shell 牽涉到每個人的喜好。 如果您是一個 C 程式設計師,那對於使用像是 tcsh(1) 這種 C-like 的 shell 可能會感到較容易上手。 如果是 Linux™ 的使用者,那您也許會想要用 bash。 每一個 Shell 都有自已獨特之處,至於這些特點能不能符合使用者的喜好,就是您選擇 shell 的重點了。

常見的 Shell 功能之一就是檔名自動補齊。 首先輸入指令或檔案的前幾個字母,然後按下 Tab 鍵,Shell 就會自動把指令或是檔案名稱剩餘的部份補齊。 假設您有兩個檔案分別叫作 foobarfootball。 要刪掉 foobar,那麼可以輸入 rm foo 然後按下 Tab 來補齊檔名。

但 Shell 只顯示了 rm foo,這代表它沒有辦法完全自動補齊檔名,因為有不只一個檔名符合條件。 foobarfootball 都是 foo 開頭的檔名。 有一些 Shell 會有嗶的音效或者顯示所有符符條件的檔名。 使用者只需要多打幾個字元來分辦想要的檔名。 輸入 t 然後再按 Tab 一次,那 Shell 就能夠替您把剩下的檔名填滿了。

Shell 的另一項特點是使用了環境變數。 環境變數是以變數與鍵值 (Variable/Key) 的對應關係儲存於 Shell 的環境,任何由該 Shell 所產生的程序都可以讀取此環境變數, 因此環境變數儲存了許多程序的設定。 常用環境變數 提供了常見的環境變數與其涵義的清單。 請注意環境變數的名稱永遠以大寫表示。

表 4. 常用環境變數
變數說明

USER

目前登入的使用者名稱。

PATH

以冒號 (:) 隔開的目錄列表,用以搜尋執行檔的路徑。

DISPLAY

若存在這個環境變數,則代表 Xorg 顯示器的網路名稱。

SHELL

目前使用的 Shell。

TERM

使用者終端機類型的名稱,用來判斷終端機有那些功能。

TERMCAP

用來執行各種終端機功能的終端機跳脫碼 (Terminal escape code) 的資料庫項目。

OSTYPE

作業系統的類型。

MACHTYPE

系統的 CPU 架構。

EDITOR

使用者偏好的文字編輯器。

PAGER

使用者偏好的文字分頁檢視工具。

MANPATH

以冒號 (:) 隔開的目錄列表,用以搜尋使用手冊的路徑。

在不同的 Shell 底下設定環境變數的方式也有所不同。 在 tcsh(1)csh(1),使用 setenv 來設定環境變數。 在 sh(1)bash 則使用 export 來設定目前環境的變數。 以下範例將 tcsh(1) Shell 下的 EDITOR 環境變數從預設值更改為 /usr/local/bin/emacs

% setenv EDITOR /usr/local/bin/emacs

相同功能的指令在 bash 下則是:

% export EDITOR="/usr/local/bin/emacs"

要展開以顯示目前環境變數中的值,只要在指令列輸入環境變數之前加上 $ 字元。 舉例來說,echo $TERM 會顯示出目前 $TERM 的設定值。

Shell 中有特殊字元用來表示特殊資料,我們將其稱作 Meta-character。 其中最常見的 Meta-character 是 * 字元,它代表了檔名中的任意字元。 Meta-character 可以用在搜尋檔名,舉例來說,輸入 echo * 會和輸入 ls 得到幾乎相同的結果,這是因為 shell 會將所有符合 * 字元的檔案由 echo 顯示出來。

為了避免 Shell 轉譯這些特殊字元,我們可以在這些特殊字元前放一個反斜線 (\) 字元使他們跳脫 (Escape) Shell 的轉譯。舉例來說,echo $TERM 會印出你目前終端機的設定, echo \$TERM 則會直接印出 $TERM 這幾個字。

3.9.1. 變更 Shell

永久變更 Shell 最簡單的方法就是透過 chsh 指令。 執行 chsh 將會使用環境變數中 EDITOR 指定的文字編輯器,如果沒有設定,則預設是 vi(1)。 請修改 Shell: 為新的 Shell 的完整路徑。

或者,使用 chsh -s, 來直接設定 Shell 而不開啟文字編輯器。 例如, 假設想把 Shell 更改為 bash

% chsh -s /usr/local/bin/bash

新的 Shell 必須已列於 /etc/shells 裡頭。 若是依 安裝應用程式:套件與 Port 說明由 Port 套件集來裝的 Shell, 那就會自動列入至該檔案裡。 若仍缺少,請使用以下指令加入檔案 (請將路徑替換為新的 Shell 的路徑):

# echo /usr/local/bin/bash >> /etc/shells

然後重新執行 chsh(1)

3.9.2. 進階 Shell 技巧

UNIX™ Shell 不只是指令的直譯器,它是一個強大的工具可讓使用者執行指令、重新導向指令的輸出、重新導向指令的輸入並將指令串連在一起來改進最終指令的輸出結果。當這個功能與內建的指令混合使用時,可提供一個可以最佳化效率的環境給使用者。

Shell 重新導向是將一個指令的輸出或輸入傳送給另一個指令或檔案。例如,要擷取 ls(1) 指令的輸出到一個檔案,可以重新導向輸出:

% ls > directory_listing.txt

目錄的內容現在會列到 directory_listing.txt 中,部份指令可以讀取輸入,例如 sort(1)。要排序這個清單,可重新導向輸入:

% sort < directory_listing.txt

輸入的內容會被排序後呈現在畫面上,要重新導向該輸入到另一個檔案,可以重新導向 sort(1) 的出輸:

% sort < directory_listing.txt > sorted.txt

於上述所有的範例中,指令會透過檔案描述符 (File descriptor) 來執行重新導向。每個 UNIX™ 系統都有檔案描述符,其中包含了標準輸入 (stdin)、標準輸出 (stdout) 以及標準錯誤 (stderr)。每一種檔案描述符都有特定的用途,輸入可能來自鍵盤或滑鼠、任何可能提供輸入的來源,輸出則可能是螢幕或印表機中的紙張,而錯誤則為任何可能用來診斷的資訊或錯誤訊息。這三種皆被認為是以 I/O 為基礎的檔案描述符,有些也會被當做串流。

透過使用這些檔案描述符,Shell 能夠讓輸出與輸入在各種指令間傳遞與重新導向到或自檔案。另一種重新導向的方式是使用管線運算子 (Pipe operator)。

UNIX™ 的管線運算子,即 "|",可允許指令的輸出可直接傳遞或導向到另一個程式。基本上,管線運算子允許指令的標準輸出以標準輸入傳遞給另一個指令,例如:

% cat directory_listing.txt | sort | less

在這個例子中,directory_listing.txt 的內容會被排序然後輸出傳遞給 less(1),這可讓使用者依自己的閱讀步調捲動輸出的結果,避免結果直接捲動出畫面。

3.10. 文字編輯器

在 FreeBSD 中有許多設定必須透過編輯文字檔完成。 因此,若能熟悉文字編輯器是再好不過的。 FreeBSD 本身就內建幾種文字編輯器, 您也可以透過 Port 套件集來安裝其他的文字編輯器。

最簡單易學的文字編輯器叫做 ee(1),意為簡易的編輯器 (Easy Editor)。 要開始使用這個編輯器, 只需輸入 ee filename,其中 filename 代表你想要編輯的檔案名稱。 在編輯器中, 所有編輯器的功能與操作都顯示在螢幕的上方。 其中的插入符號 (^) 代表鍵盤上的 Ctrl 鍵,所以 ^e 代表的是 Ctrl+e。 若要結束 ee(1),請按下 Esc 鍵,接著選擇 "leave editor" 即可。 此時如果該檔案有修改過,編輯器會提醒你是否要存檔。

FreeBSD 同時也內建功能強大的文字編輯器,像是vi(1)。 其他編輯器如 editors/emacseditors/vim 則由 FreeBSD Port 套件集提供。 這些編輯器提供更強的功能,但是也比較難學習。 長期來看學習 vim 或 Emacs 會在日後為您省下更多的時間。

有許多應用程式在修改檔案或需要輸入時會自動開啟文字編輯器,要更改預設的編輯器可設定 EDITOR 環境變數如 Shell 所說明。

3.11. 裝置及裝置節點

裝置 (Device) 一詞大多是跟硬體比較有關的術語,包括磁碟、印表機、顯示卡和鍵盤。 FreeBSD 開機過程當中,開機訊息 (Boot Message) 中主要是會列出偵測到的硬體裝置,開機訊息的複本也會存放在 /var/run/dmesg.boot

每一個裝置都有一個裝置名稱及編號,舉例來說 ada0 是第一台 SATA 硬碟,而 kbd0 則代表鍵盤。

在 FreeBSD 中大多數的裝置必須透過裝置節點 (Device Node) 的特殊檔案來存取,這些檔案會放置在 /dev

3.12. 操作手冊

在 FreeBSD 中,最詳細的文件莫過於操作手冊。 幾乎在系統上所有程式都會有簡短的操作手冊來介紹該程式的基本操作以及可用的參數。 這些操作手冊可以使用 man 指令來檢視:

% man command

其中 command 想要瞭解指令的名稱。 舉例,要知道 ls(1) 的詳細用法,就可以打:

% man ls

操作手冊被分成很多個章節,每個章節有不同的主題。 在 FreeBSD 中操作手冊有以下章節:

  1. 使用者指令。

  2. 系統呼叫 (System call) 與錯誤編號。

  3. C 程式庫函數。

  4. 裝置驅動程式。

  5. 檔案格式。

  6. 遊戲及其他程式。

  7. 其他資訊。

  8. 系統維護與操作指令。

  9. 系統核心介面。

有些情況會有同樣主題會同時出現在不同章節。 舉個例子,系統內會有 chmod 使用者指令,但同時也有 chmod() 系統呼叫。 在這種情況,要告訴 man(1) 要查詢的章節編號:

% man 1 chmod

如此一來就會查詢使用者指令 chmod(1)。 通常在寫文件時會把有參考到特定章節的號碼寫在括號內。 所以 chmod(1) 就是指使用者指令,而 chmod(2) 則是指系統呼叫。

若不曉得操作手冊的名稱,可以使用 man -k 來以關鍵字查詢所有操作手冊的描述:

% man -k mail

這個指令會顯示所有描述中有使用到關鍵字 "mail" 的指令。 這等同使用 apropos(1)

想要閱讀所有在 /usr/bin 底下的指令說明則可輸入:

% cd /usr/bin
% man -f * | more

% cd /usr/bin
% whatis * |more

3.12.1. GNU Info 檔

FreeBSD 有許多應用程式與工具來自自由軟體基金會 (Free Software Foundation, FSF)。 除了操作手冊之外,這些程式提供了另外一種更具有彈性的超文字文件叫做 info 檔。 這些檔案可以使用 info(1) 指令來閱讀,或者若有裝 editors/emacs 亦可透過 emacs 的 info 模式閱讀。

要使用 info(1) 指令,只需輸入:

% info

要查詢簡單說明請按 h 鍵,若要查訊快速指令參考請按 ? 鍵。


本文及其他文件,可由此下載 https://download.freebsd.org/ftp/doc/

若有 FreeBSD 方面疑問,請先閱讀 FreeBSD 相關文件 ,如不能解決的話,再洽詢 <freebsd-questions@FreeBSD.org>.
關於本文件的問題,請洽詢 <freebsd-doc@FreeBSD.org>.