grub2詳解(翻譯和整理官方手冊)

来源:http://www.cnblogs.com/f-ck-need-u/archive/2017/06/29/7094693.html
-Advertisement-
Play Games

翻譯了grub2官方手冊的絕大部分內容,然後自己整理了一下。因為內容有點雜,所以章節安排上可能不是太合理,敬請諒解。 本文目錄: 1.1 基礎內容 1.2 安裝grub2 1.3 grub2配置文件 1.4 命令行和菜單項中的命令 1.5 幾個常見的內置變數 1.6 grub配置和安裝示例 1.7 ...


翻譯了grub2官方手冊的絕大部分內容,然後自己整理了一下。因為內容有點雜,所以章節安排上可能不是太合理,敬請諒解。


本文目錄:

1.1 基礎內容

1.2 安裝grub2

1.3 grub2配置文件

1.4 命令行和菜單項中的命令

1.5 幾個常見的內置變數

1.6 grub配置和安裝示例

1.7 傳統grub簡述


 

本文主要介紹的是grub2,在文末對傳統grub進行了簡述,但在grub2的內容部分中包含了很多grub2和傳統grub的對比。

如果僅僅是想知道grub2中的boot.img/core.img/diskboot.img/kernel.img或者傳統grub中stage1/stage1_5/stage2文件的作用,請直接跳至相關內容處閱讀。

1.1 基礎內容

1.1.1 grub2和grub的區別

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Changes-from-GRUB-Legacy.html#Changes-from-GRUB-Legacy

只說明幾個主要的:

1.配置文件的名稱改變了。在grub中,配置文件為grub.conf或menu.lst(grub.conf的一個軟鏈接),在grub2中改名為grub.cfg。

2.grub2增添了許多語法,更接近於腳本語言了,例如支持變數、條件判斷、迴圈。

3.grub2中,設備名稱從1開始,而在grub中是從0開始的。

4.grub2使用img文件,不再使用grub中的stage1、stage1.5和stage2。

5.支持圖形界面配置grub,但要安裝grub-customizer包,epel源提供該包。

6.在已進入操作系統環境下,不再提供grub命令,也就是不能進入grub互動式界面,只有在開機時才能進入,算是一大缺憾。

7.在grub2中沒有了好用的find命令,算是另一大缺憾。

1.1.2 命名習慣和文件路徑表示方式

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Naming-convention.html#Naming-convention

(fd0)           :表示第一塊軟盤
(hd0,msdos2)    :表示第一塊硬碟的第二個mbr分區。grub2中分區從1開始編號,傳統的grub是從0開始編號的
(hd0,msdos5)    :表示第一塊硬碟的第一個邏輯分區
(hd0,gpt1)      :表示第一塊硬碟的第一個gpt分區
/boot/vmlinuz   :相對路徑,基於根目錄,表示根目錄下的boot目錄下的vmlinuz,
                :如果設置了根目錄變數root為(hd0,msdos1),則表示(hd0,msdos1)/boot/vmlinuz
(hd0,msdos1)/boot/vmlinuz:絕對路徑,表示第一硬碟第一分區的boot目錄下的vmlinuz文件

1.1.3 grub2引導操作系統的方式

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/General-boot-methods.html#General-boot-methods

grub2支持兩種方式引導操作系統:

  • 直接引導:(direct-load)直接通過預設的grub2 boot loader來引導寫在預設配置文件中的操作系統
  • 鏈式引導:(chain-load)使用預設grub2 boot loader鏈式引導另一個boot loader,該boot loader將引導對應的操作系統

一般只使用第一種方式,只有想引導grub預設不支持的操作系統時才會使用第二種方式。

1.1.4 grub2程式和傳統grub程式安裝後的文件分佈

在傳統grub軟體安裝完後,在/usr/share/grub/RELEASE/目錄下會生成一些stage文件。

[root@xuexi ~]# ls /usr/share/grub/x86_64-redhat/
e2fs_stage1_5      ffs_stage1_5       jfs_stage1_5       reiserfs_stage1_5  stage2             ufs2_stage1_5      xfs_stage1_5
fat_stage1_5       iso9660_stage1_5   minix_stage1_5     stage1             stage2_eltorito    vstafs_stage1_5

在grub2軟體安裝完後,會在/usr/lib/grub/i386-pc/目錄下生成很多模塊文件和img文件,還包括一些lst列表文件。

[root@server7 ~]# ls /usr/lib/grub/i386-pc/*.mod | wc -l
257

[root@server7 ~]# ls -lh /usr/lib/grub/i386-pc/*.lst   
-rw-r--r--. 1 root root 3.7K Nov 24  2015 /usr/lib/grub/i386-pc/command.lst
-rw-r--r--. 1 root root  936 Nov 24  2015 /usr/lib/grub/i386-pc/crypto.lst
-rw-r--r--. 1 root root  214 Nov 24  2015 /usr/lib/grub/i386-pc/fs.lst
-rw-r--r--. 1 root root 5.1K Nov 24  2015 /usr/lib/grub/i386-pc/moddep.lst
-rw-r--r--. 1 root root  111 Nov 24  2015 /usr/lib/grub/i386-pc/partmap.lst
-rw-r--r--. 1 root root   17 Nov 24  2015 /usr/lib/grub/i386-pc/parttool.lst
-rw-r--r--. 1 root root  202 Nov 24  2015 /usr/lib/grub/i386-pc/terminal.lst
-rw-r--r--. 1 root root   33 Nov 24  2015 /usr/lib/grub/i386-pc/video.lst

[root@server7 ~]# ls -lh /usr/lib/grub/i386-pc/*.img
-rw-r--r--. 1 root root  512 Nov 24  2015 /usr/lib/grub/i386-pc/boot_hybrid.img
-rw-r--r--. 1 root root  512 Nov 24  2015 /usr/lib/grub/i386-pc/boot.img
-rw-r--r--. 1 root root 2.0K Nov 24  2015 /usr/lib/grub/i386-pc/cdboot.img
-rw-r--r--. 1 root root  512 Nov 24  2015 /usr/lib/grub/i386-pc/diskboot.img
-rw-r--r--. 1 root root  28K Nov 24  2015 /usr/lib/grub/i386-pc/kernel.img
-rw-r--r--. 1 root root 1.0K Nov 24  2015 /usr/lib/grub/i386-pc/lnxboot.img
-rw-r--r--. 1 root root 2.9K Nov 24  2015 /usr/lib/grub/i386-pc/lzma_decompress.img
-rw-r--r--. 1 root root 1.0K Nov 24  2015 /usr/lib/grub/i386-pc/pxeboot.img

1.1.5 boot loader和grub的關係

當使用grub來管理啟動菜單時,那麼boot loader都是grub程式安裝的。

傳統的grub將stage1轉換後的內容安裝到MBR(VBR或EBR)中的boot loader部分,將stage1_5轉換後的內容安裝在緊跟在MBR後的扇區中,將stage2轉換後的內容安裝在/boot分區中。

grub2將boot.img轉換後的內容安裝到MBR(VBR或EBR)中的boot loader部分,將diskboot.img和kernel.img結合成為core.img,同時還會嵌入一些模塊或載入模塊的代碼到core.img中,然後將core.img轉換後的內容安裝到磁碟的指定位置處。

它們之間更具體的關係見下文。

1.1.6 grub2的安裝位置

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/BIOS-installation.html#BIOS-installation

嚴格地說是core.img的安裝位置,因為boot.img的位置是固定在MBR或VBR或EBR上的。

(1).MBR

MBR格式的分區表用於PC BIOS平臺,這種格式允許四個主分區和額外的邏輯分區。使用這種格式的分區表,有兩種方式安裝GURB:

  1. 嵌入到MBR和第一個分區中間的空間,這部分就是大眾所稱的"boot track","MBR gap"或"embedding area",它們大致需要31kB的空間;
  2. 將core.img安裝到某個文件系統中,然後使用分區的第一個扇區(嚴格地說不是第一個扇區,而是第一個block)存儲啟動它的代碼。

這兩種方法有不同的問題。

使用嵌入的方式安裝grub,就沒有保留的空閑空間來保證安全性,例如有些專門的軟體就是使用這段空間來實現許可限制的;另外分區的時候,雖然會在MBR和第一個分區中間留下空閑空間,但可能留下的空間會比這更小。

方法二安裝grub到文件系統,但這樣的grub是脆弱的。例如,文件系統的某些特性需要做尾部包裝,甚至某些fsck檢測,它們可能會移動這些block。

GRUB開發團隊建議將GRUB嵌入到MBR和第一個分區之間,除非有特殊需求,但仍必須要保證第一個分區至少是從第31kB(第63個扇區)之後才開始創建的。

現在的磁碟設備,一般都會有分區邊界對齊的性能優化提醒,所以第一個分區可能會自動從第1MB處開始創建。

(2).GPT

一些新的系統使用GUID分區表(GPT)格式,這種格式是EFI固件所指定的一部分。但如果操作系統支持的話,GPT也可以用於BIOS平臺(即MBR風格結合GPT格式的磁碟),使用這種格式,需要使用獨立的BIOS boot分區來保存GRUB,GRUB被嵌入到此分區,不會有任何風險。

當在gpt磁碟上創建一個BIOS boot分區時,需要保證兩件事:(1)它最小是31kB大小,但一般都會為此分區劃分1MB的空間用於可擴展性;(2)必須要有合理的分區類型標識(flag type)。

例如使用gun parted工具時,可以設置為bios_grub標識:

# parted /dev/sda toggle partition_num bios_grub
# parted /dev/sda set partiton_num bios_grub on

如果使用gdisk分區工具時,則分類類型設置為"EF02"。

如果使用其他的分區工具,可能需要指定guid,則可以指定其guid為"21686148-6449-6e6f-744e656564454649"。

下圖是某個bios/gpt格式的bios boot分區信息,從中可見,它大小為1M,沒有文件系統,分區表示為bios_grub。

下圖為gpt磁碟在圖形界面下安裝操作系統時創建的Bios boot分區。

1.1.7 進入grub命令行

在傳統的grub上,可以直接在bash下敲入grub命令進入命令交互模式,但grub2只能在系統啟動前進入grub交互命令行。

按下e見可以編輯所選菜單對應的grub菜單配置項,按下c鍵可以進入grub命令行交互模式。

1.2 安裝grub2

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Installing-GRUB-using-grub_002dinstall.html#Installing-GRUB-using-grub_002dinstall

這裡的安裝指的不是安裝grub程式,而是安裝Boot loader,但一般都稱之為安裝grub,且後文都是這個意思。

1.2.1 grub安裝命令

安裝方式非常簡單,只需調用grub2-install,然後給定安裝到的設備名即可。

shell> grub2-install /dev/sda

這樣的安裝方式,預設會將img文件放入到/boot目錄下,如果想自定義放置位置,則使用--boot-directory選項指定,可用於測試練習grub的時候使用,但在真實的grub環境下不建議做任何改動。

shell> grub2-install --boot-director=/mnt/boot /dev/fd0

如果是EFI固件平臺,則必須掛載好efi系統分區,一般會掛在/boot/efi下,這是預設的,此時可直接使用grub2-install安裝。

shell> grub2-install

如果不是掛載在/boot/efi下,則使用--efi-directory指定efi系統分區路徑。

shell> grub2-install --efi-directory=/mnt/efi

grub2-install實際上是一個shell腳本,用於調用其他工具,真正的功能都是其他工具去完成的,所以如果非常熟悉grub內部命令和機制,完全可以不用grub2-install。

對應傳統的grub安裝命令為grub-install,用法和grub2-install一樣。

1.2.2 各種img和stage文件的說明

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Images.html#Images

img文件是grub2生成的,stage文件是傳統grub生成的。下麵是各種文件的說明。

1.2.2.1 grub2中的img文件

grub2生成了好幾個img文件,有些分佈在/usr/lib/grub/i386-pc目錄下,有些分佈在/boot/grub2/i386-pc目錄下,它們之間的關係,相信看了下文之後就會明白了。

下圖描述了各個img文件之間的關係。其中core.img是動態生成的,路徑為/boot/grub2/i386-pc/core.img,而其他的img則存在於/usr/lib/grub/i386-pc目錄下。當然,在安裝grub時,boot.img會被拷貝到/boot/grub2/i386-pc目錄下。

(1)boot.img

在BIOS平臺下,boot.img是grub啟動的第一個img文件,它被寫入到MBR中或分區的boot sector中,因為boot sector的大小是512位元組,所以該img文件的大小也是512位元組。

boot.img唯一的作用是讀取屬於core.img的第一個扇區並跳轉到它身上,將控制權交給該扇區的img。由於體積大小的限制,boot.img無法理解文件系統的結構,因此grub2-install將會把core.img的位置硬編碼到boot.img中,這樣就一定能找到core.img的位置。

(2)core.img

core.img根據diskboot.img、kernel.img和一系列的模塊被grub2-mkimage程式動態創建。core.img中嵌入了足夠多的功能模塊以保證grub能訪問/boot/grub,並且可以載入相關的模塊實現相關的功能,例如載入啟動菜單、載入目標操作系統的信息等,由於grub2大量使用了動態功能模塊,使得core.img體積變得足夠小。

core.img中包含了多個img文件的內容,包括diskboot.img/kernel.img等。

core.img的安裝位置隨MBR磁碟和GPT磁碟而不同,這在上文中已經說明過了。

(3)diskboot.img

如果啟動設備是硬碟,即從硬碟啟動時,core.img中的第一個扇區的內容就是diskboot.img。diskboo.img的作用是讀取core.img中剩餘的部分到記憶體中,並將控制權交給kernel.img,由於此時還不識別文件系統,所以將core.img的全部位置以block列表的方式編碼,使得diskboot.img能夠找到剩餘的內容。

該img文件因為占用一個扇區,所以體積為512位元組。

(4)cdboot.img

如果啟動設備是光碟機(cd-rom),即從光碟機啟動時,core.img中的第一個扇區的的內容就是cdboo.img。它的作用和diskboot.img是一樣的。

(5)pexboot.img

如果是從網路的PXE環境啟動,core.img中的第一個扇區的內容就是pxeboot.img。

(6)kernel.img

kernel.img文件包含了grub的基本運行時環境:設備框架、文件句柄、環境變數、救援模式下的命令行解析器等等。很少直接使用它,因為它們已經整個嵌入到了core.img中了。註意,kernel.img是grub的kernel,和操作系統的內核無關。

如果細心的話,會發現kernel.img本身就占用28KB空間,但嵌入到了core.img中後,core.img文件才只有26KB大小。這是因為core.img中的kernel.img是被壓縮過的。

(7)lnxboot.img

該img文件放在core.img的最前部位,使得grub像是linux的內核一樣,這樣core.img就可以被LILO的"image="識別。當然,這是配合LILO來使用的,但現在誰還適用LILO呢?

(8)*.mod

各種功能模塊,部分模塊已經嵌入到core.img中,或者會被grub自動載入,但有時也需要使用insmod命令手動載入。

1.2.2.2 傳統grub中的stage文件

grub2的設計方式和傳統grub大不相同,因此和stage之間的對比關係其實沒那麼標準,但是將它們拿來比較也有助於理解img和stage文件的作用。

stage文件也分佈在兩個地方:/usr/share/grub/RELEASE目錄下和/boot/grub目錄下,/boot/grub目錄下的stage文件是安裝grub時從/usr/share/grub/RELEASE目錄下拷貝過來的。

(1)stage1

stage1文件在功能上等價於boot.img文件。目的是跳轉到stage1_5或stage2的第一個扇區上。

(2)*_stage1_5

*stage1_5文件包含了各種識別文件系統的代碼,使得grub可以從文件系統中讀取體積更大功能更複雜的stage2文件。從這一方面考慮,它類似於core.img中載入對應文件系統模塊的代碼部分,但是core.img的功能遠比stage1_5多。

stage1_5一般安裝在MBR後、第一個分區前的那段空閑空間中,也就是MBR gap空間,它的作用是跳轉到stage2的第一個扇區。

其實傳統的grub在某些環境下是可以不用stage1_5文件就能正常運行的,但是grub2則不能缺少core.img。

(3)stage2

stage2的作用是載入各種環境和載入內核,在grub2中沒有完全與之相對應的img文件,但是core.img中包含了stage2的所有功能。

當跳轉到stage2的第一個扇區後,該扇區的代碼負責載入stage2剩餘的內容。

註意,stage2是存放在磁碟上的,並沒有像core.img一樣嵌入到磁碟上。

(4)stage2_eltorito

功能上等價於grub2中的core.img中的cdboot.img部分。一般在製作救援模式的grub時才會使用到cd-rom相關文件。

(5)pxegrub

功能上等價於grub2中的core.img中的pxeboot.img部分。

1.2.3 安裝grub涉及的過程

安裝grub2的過程大體分兩步:一是根據/usr/lib/grub/i386-pc/目錄下的文件生成core.img,並拷貝boot.img和core.img涉及的某些模塊文件到/boot/grub2/i386-pc/目錄下;二是根據/boot/grub2/i386-pc目錄下的文件向磁碟上寫boot loader。

當然,到底是先拷貝,還是先寫boot loader,沒必要去搞清楚,只要/boot/grub2/i386-pc下的img文件一定能通過grub2相關程式再次生成boot loader。所以,既可以認為/boot/grub2/i386-pc目錄下的img文件是boot loader的特殊備份文件,也可以認為是boot loader的源文件。

不過,img文件和boot loader的內容是不一致的,因為img文件還要通過grub2相關程式來轉換才是真正的boot loader。

對於傳統的grub而言,拷貝的不是img文件,而是stage文件。

以下是安裝傳統grub時,grub做的工作。很不幸,grub2上沒有該命令,也沒有與之等價的命令。

grub> setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  15 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded
Done.

首先檢測各stage文件是否存在於/boot/grub目錄下,隨後嵌入stage1_5到磁碟上,該文件系統類型的stage1_5占用了15個扇區,最後安裝stage1,並告知stage1 stage1_5的位置是第1到第15個扇區,之所以先嵌入stage1_5再嵌入stage1就是為了讓stage1知道stage1_5的位置,最後還告知了stage1 stage2和配置文件menu.lst的路徑。

1.3 grub2配置文件

grub2的預設配置文件為/boot/grub2/grub.cfg,該配置文件的寫法彈性非常大,但絕大多數需要修改該配置文件時,都只需修改其中一小部分內容就可以達成目標。

grub2-mkconfig程式可用來生成符合絕大多數情況的grub.cfg文件,預設它會自動嘗試探測有效的操作系統內核,並生成對應的操作系統菜單項。使用方法非常簡單,只需一個選項"-o"指定輸出文件即可。

shell> grub2-mkconfig -o /boot/grub2/grub.cfg

1.3.1 通過/etc/default/grub文件生成grub.cfg

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Simple-configuration.html#Simple-configuration

grub2-mkconfig是根據/etc/default/grub文件來創建配置文件的該文件中定義的是grub的全局巨集,修改內置的巨集可以快速生成grub配置文件。實際上在/etc/grub.d/目錄下還有一些grub配置腳本,這些shell腳本讀取一些腳本配置文件(如/etc/default/grub),根據指定的邏輯生成grub配置文件。若有興趣,不放讀一讀/etc/grub.d/10_linux文件,它指導了創建grub.cfg的細節,例如如何生成啟動菜單。

[root@xuexi ~]# ls /etc/grub.d/
00_header  00_tuned  01_users  10_linux  20_linux_xen  20_ppc_terminfo  30_os-prober  40_custom  41_custom  README

在/etc/default/grub中,使用"key=vaule"的格式,key全部為大小字母,如果vaule部分包含了空格或其他特殊字元,則需要使用引號包圍。

例如,下麵是一個/etc/default/grub文件的示例:

[root@xuexi ~]# cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

雖然可用的巨集較多,但可能用的上的就幾個:GRUB_DEFAULT、GRUB_TIMEOUT、GRUB_CMDLINE_LINUX和GRUB_CMDLINE_LINUX_DEFAULT。

以下列出了部分key。

(1).GRUB_DEFAULT

預設的菜單項,預設值為0。其值可為數值N,表示從0開始計算的第N項是預設菜單,也可以指定對應的title表示該項為預設的菜單項。使用數值比較好,因為使用的title可能包含了容易改變的設備名。例如有如下菜單項:

menuentry 'Example GNU/Linux distribution' --class gnu-linux --id example-gnu-linux {
    ...
}

如果想將此菜單設為預設菜單,則可設置"GRUB_DEFAULT=example-gnu-linux"。

如果GRUB_DEFAULT的值設置為"saved",則表示預設的菜單項是"GRUB_SAVEDEFAULT"或"grub-set-default"所指定的菜單項。

(2).GRUB_SAVEDEFAULT

預設該key的值未設置。如果該key的值設置為true時,如果選定了某菜單項,則該菜單項將被認為是新的預設菜單項。該key只有在設置了"GRUB_DEFAULT=saved"時才有效。

不建議使用該key,因為GRUB_DEFAULT配合grub-set-default更方便。

(3).GRUB_TIMEOUT

在開機選擇菜單項的超時時間,超過該時間將使用預設的菜單項來引導對應的操作系統。預設值為5秒。等待過程中,按下任意按鍵都可以中斷等待。

設置為0時,將不列出菜單直接使用預設的菜單項引導與之對應的操作系統,設置為"-1"時將永久等待選擇。

是否顯示菜單,和"GRUB_TIMEOUT_STYLE"的設置有關。

(4).GRUB_TIMEOUT_STYLE

如果該key未設置值或者設置的值為"menu",則列出啟動菜單項,並等待"GRUB_TIMEOUT"指定的超時時間。

如果設置為"countdown"和"hidden",則不顯示啟動菜單項,而是直接等待"GRUB_TIMEOUT"指定的超時時間,如果超時了則啟動預設菜單項並引導對應的操作系統。在等待過程中,按下"ESC"鍵可以列出啟動菜單。設置為countdown和hidden的區別是countdown會顯示超時時間的剩餘時間,而hidden則完全隱藏超時時間。

(5).GRUB_DISTRIBUTOR

設置發行版的標識名稱,一般該名稱用來作為菜單的一部分,以便區分不同的操作系統。

(6).GRUB_CMDLINE_LINUX

添加到菜單中的內核啟動參數。例如:

GRUB_CMDLINE_LINUX="crashkernel=ro root=/dev/sda3 biosdevname=0 net.ifnames=0 rhgb quiet"

(7).GRUB_CMDLINE_LINUX_DEFAULT

除非"GRUB_DISABLE_RECOVERY"設置為"true",否則該key指定的預設內核啟動參數將生成兩份,一份是用於預設啟動參數,一份用於恢復模式(recovery mode)的啟動參數。

該key生成的預設內核啟動參數將添加在"GRUB_CMDLINE_LINUX"所指定的啟動參數之後。

(8).GRUB_DISABLE_RECOVERY

該項設置為true時,將不會生成恢復模式的菜單項。

(9).GRUB_DISABLE_LINUX_UUID

預設情況下,grub2-mkconfig在生產菜單項的時候將使用uuid來標識Linux 內核的根文件系統,即"root=UUID=..."。

例如,下麵是/boot/grub2/grub.cfg中某菜單項的部分內容。

menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8' {

        ......

        linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto biosdevname=0 net.ifnames=0 quiet LANG=en_US.UTF-8

        initrd16 /initramfs-3.10.0-327.el7.x86_64.img

}

雖然使用UUID的方式更可靠,但有時候不太方便,所以可以設置該key為true來禁用。

(10).GRUB_BACKGROUND

設置背景圖片,背景圖片必須是grub可讀的,圖片文件名尾碼必須是".png"、".tga"、".jpg"、".jpeg",在需要的時候,grub會按比例縮小圖片的大小以適配屏幕大小。

(11).GRUB_THEME

設置grub菜單的主題。

(12).GRUB_GFXPAYLOAD_LINUX

設置為"text"時,將強制使用文本模式啟動Linux。在某些情況下,可能不支持圖形模式。

(13).GRUB_DISABLE_OS_PROBER

預設情況下,grub2-mkconfig會嘗試使用os-prober程式(如果已經安裝的話,預設應該都裝了)探測其他可用的操作系統內核,併為其生成對應的啟動菜單項。設置為"true"將禁用自動探測功能。

(14).GRUB_DISABLE_SUBMENU

預設情況下,grub2-mkconfig如果發現有多個同版本的或低版本的內核時,將只為最高版本的內核生成頂級菜單,其他所有的低版本內核菜單都放入子菜單中,設置為"y"將全部生成為頂級菜單。

(15).GRUB_HIDDEN_TIMEOUT(已廢棄,但為了向後相容,仍有效)

使用"GRUB_TIMEOUT_STYLE={countdown|hidden}"替代該項

(16).GRUB_HIDDEN_TIMEOUT_QUIET(已廢棄,但為了向後相容,仍有效)

配合GRUB_HIDDEN_TIMEOUT使用,可以使用GRUB_TIMEOUT_STYLE=countdown來替代這兩項。

1.3.2 腳本方式直接編寫grub.cfg文件

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Shell_002dlike-scripting.html#Shell_002dlike-scripting

  • 註釋符:從#開始的字元都被認為是註釋,所以grub支持行中註釋
  • 連接操作符:{ } | & $ ; < >
  • 保留關鍵字和符號:! [[ ]] { } case do done elif else esac fi for function if in menuentry select then time until while。並非所有的關鍵字都有用,只是為了日後的功能擴展而提前提供的。
  • 引號和轉義符

對於特殊的字元需要轉義。有三種方式轉義:使用反斜線、使用單引號、使用雙引號。

反斜線轉義方式和shell一樣。

單引號中的所有字元串都是字面意思,沒有任何特殊意義,即使單引號中的轉義符也被認為是純粹的字元。所以'\''是無法保留單引號的。單引號需要使用雙引號來轉移,所以應該寫"'"。

雙引號和單引號作用一樣,但它不能轉義某幾個特殊字元,包括"$"和"\"。對於雙引號中的"$"符號,它任何時候都保留本意。對於"\",只有反斜線後的字元是'$'、'"'、'\'時才表示轉義的意思,另外 ,某行若以反斜線結尾,則表示續行,但官方不建議在grub.cfg中使用續行符。

  • 變數擴展

使用$符號引用變數,也可以使用${var}的方式引用var變數。

支持位置變數,例如$1引用的是第一個參數。

還支持特殊的變數,如$?表示上一次命令的退出狀態碼。如果使用了位置變數,則還支持$*、$@和$#,$@代表的所有參數整體,各參數之間是不可分割的,$@也代表所有變數,但$@的各參數是可以被分割的,$#表示參數的個數。

  • 簡單的命令

可以在grub.cfg中使用簡單的命令。各命令之間使用換行符或分號表示該命令結束。

如果在命令前使用了"!",則表示邏輯取反。

  • 迴圈結構:for name in word …; do list; done
  • 迴圈結構:while cond; do list; done
  • 迴圈結構:until cond; do list; done
  • 條件判斷結構:if list; then list; [elif list; then list;] … [else list;] fi
  • 函數結構:function name { command; … }
  • 菜單項命令:menuentry title [--class=class …] [--users=users] [--unrestricted] [--hotkey=key] [--id=id] { command; … }

這是grub.cfg中最重要的項,官方原文:https://www.gnu.org/software/grub/manual/html_node/menuentry.html#menuentry

該命令定義了一個名為title的grub菜單項。當開機時選中該菜單項時,grub會將chosen環境變數的值賦給"--id"(如果給定了"--id"的話),執行大括弧中的命令列表,如果直到最後一個命令都全部執行成功,且成功載入了對應的內核後,將執行boot命令。隨後grub就將控制權交給了操作系統內核。

--class:該選項用於將菜單分組,從而使得grub可以通過主題樣式為不同組的菜單顯示不同的樣式風格。一個menuentry中,可以使用多次class表示將該菜單分到多個組中去。

--users:該選項限定只有此處列出的用戶才能訪問該菜單項,不指定該選項時將表示所有用戶都能訪問該菜單。

--unrestricted:該選項表示所有用戶都有權訪問該菜單項。

--hotkey:該選項為該菜單項關聯一個熱鍵,也就是快捷鍵,關聯熱鍵後只要按下該鍵就會選中該菜單。熱鍵只能是字母鍵、backspace鍵、tab鍵或del鍵。

--id:該選項為該菜單關聯一個唯一的數值。id的值可以由ASCII字母、數字//下劃線組成,且不得以數字開頭。

所有其他的參數包括title都被當作位置參數傳遞給大括弧中的命令,但title總是$1,除title外的其餘參數,位置值從前向後類推。

  • break [n]:強制退出for/while/until迴圈
  • continue [n]:跳到下一次迭代,即進入下一次迴圈
  • return [n]:指定返回狀態碼
  • setparams [arg] …:從$1開始替換位置參數
  • shift [n]:踢掉前n個參數,使得第n+1個參數變為$1,但和shell中不一樣的是,踢掉了前n個參數後,從$#-n+1到$#這些參數的位置不變

具體如何編寫grub.cfg文件,繼續看下文的命令和變數。

1.4 命令行和菜單項中的命令

官方手冊原文:https://www.gnu.org/software/grub/manual/html_node/Commands.html#Commands

grub2支持很多命令,有些命令只能在互動式命令行下使用,有些命令可用在配置文件中。在救援模式下,只有insmod、ls、set和unset命令可用。

無需掌握所有的命令,掌握用的上的幾個命令即可。

1.4.1 help命令

help [pattern]

顯示能匹配到pattern的所有命令的說明信息和usage信息,如果不指定patttern,將顯示所有命令的簡簡訊息。

例如"help cmos"。

1.4.2 boot命令

用於啟動已載入的操作系統。

只在互動式命令行下可用。其實在menuentry命令的結尾就隱含了boot命令。

1.4.3 set和unset命令

set [envvar=value]
unset envvar

前者設置環境變數envvar的值,如果不給定參數,則列出當前環境變數。

後者釋放環境變數envvar。

1.4.4 lsmod命令和insmod命令

分別用於列出已載入的模塊和調用指定的模塊。

註意,若要導入支持ext文件系統的模塊時,只需導入ext2.mod即可,實際上也沒有ext3和ext4對應的模塊。

1.4.5 linux和linux16命令

linux file [kernel_args]
linux16 file [kernel_args]

都表示裝載指定的內核文件,並傳遞內核啟動參數。linux16表示以傳統的16位啟動協議啟動內核,linux表示以32位啟動協議啟動內核,但linux命令比linux16有一些限制。但絕大多數時候,它們是可以通用的。

在linux或linux16命令之後,必須緊跟著使用init或init16命令裝載init ramdisk文件。

一般為/boot分區下的vmlinuz-RELEASE_NUM文件。

但在grub環境下,boot分區被當作root分區,即根分區,假如boot分區為第一塊磁碟的第一個分區,則應該寫成:

linux (hd0,msdos1)/vmlinuz-XXX

或者相對路徑的:

set root='hd0,msdos1'

linux /vmlinuz-XXX

在grub階段可以傳遞內核的啟動參數(內核的參數包括3類:編譯內核時參數,啟動時參數和運行時參數),可以傳遞的啟動參數非常非常多,完整的啟動參數列表見:http://redsymbol.net/linux-kernel-boot-parameters。這裡只列出幾個常用的:

init=   :指定Linux啟動的第一個進程init的替代程式。
root=   :指定根文件系統所在分區,在grub中,該選項必須給定。
ro,rw   :啟動時,根分區以只讀還是可讀寫方式掛載。不指定時預設為ro。
initrd  :指定init ramdisk的路徑。在grub中因為使用了initrd或initrd16命令,所以不需要指定該啟動參數。
rhgb    :以圖形界面方式啟動系統。
quiet   :以文本方式啟動系統,且禁止輸出大多數的log message。
net.ifnames=0:用於CentOS 7,禁止網路設備使用一致性命名方式。
biosdevname=0:用於CentOS 7,也是禁止網路設備採用一致性命名方式。
             :只有net.ifnames和biosdevname同時設置為0時,才能完全禁止一致性命名,得到eth0-N的設備名。

例如:

linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=edb1bf15-9590-4195-aa11-6dac45c7f6f3 ro rhgb quiet LANG=en_US.UTF-8

另外,root啟動參數有多種定義方式,可以使用UUID的方式指定,也可以直接指定根文件系統所在分區,如"root=/dev/sda2",

1.4.6 initrd和initrd16命令

initrd file

只能緊跟在linux或linux16命令之後使用,用於為即將啟動的內核傳遞init ramdisk路徑。

同樣,基於根分區,可以使用絕對路徑,也可以使用相對路徑。路徑的表示方法和linux或linux16命令相同。例如:

linux16 /vmlinuz-0-rescue-d13bce5e247540a5b5886f2bf8aabb35 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet

initrd16 /initramfs-0-rescue-d13bce5e247540a5b5886f2bf8aabb35.img

1.4.7 search命令

search [--file|--label|--fs-uuid] [--set [var]] [--no-floppy] [--hint args] name

通過文件[--file]、捲標[--label]、文件系統UUID[--fs-uuid]來搜索設備。

如果使用了"--set"選項,則會將第一個找到的設備設置為環境變數"var"的值,預設的變數"var"為'root'。

搜索時可使用"--no-floppy"選項來禁止搜索軟盤,因為軟盤速度非常慢,已經被淘汰了。

有時候還會指定"--hint=XXX",表示優先選擇滿足提示條件的設備,若指定了多個hint條件,則優先匹配第一個hint,然後匹配第二個,依次類推。

例如:

if [ x$feature_platform_search_hint = xy ]; then

  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  367d6a77-033b-4037-bbcb-416705ead095

else

  search --no-floppy --fs-uuid --set=root 367d6a77-033b-4037-bbcb-416705ead095

fi

linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet LANG=en_US.UTF-8

initrd16 /initramfs-3.10.0-327.el7.x86_64.img

上述if語句中的第一個search中搜索uuid為"367d6a77-033b-4037-bbcb-416705ead095"的設備,但使用了多個hint選項,表示先匹配bios平臺下/boot分區為(hd0,msdos1)的設備,之後還指定了幾個hint,但因為search使用的是uuid搜索方式,所以這些hint選項是多餘的,因為單磁碟上分區的uuid是唯一的。

再舉個例子,如果某啟動設備上有兩個boot分區(如多系統共存時),分別是(hd0,msdos1)和(hd0,msdos5),如果此時不使用uuid搜索,而是使用label方式搜索:

search --no-floppy --fs-label=boot --set=root --hint=hd0,msdos5

則此時將會選中(hd0,msdos5)這個boot分區,若不使用hint,將選中(hd0,msdos1)這個boot分區。

1.4.8 true和false命令

直接返回true或false布爾值。

1.4.9 test expression和[ expression ]

計算"expression"的結果是否為真,為真時返回0,否則返回非0,主要用於if、while或until結構中。

string1 == string2

string1與string2相同

string1 != string2

string1與string2不相同

string1 < string2

string1在字母順序上小於string2

string1 <= string2

string1在字母順序上小於等於string2

string1 > string2

string1在字母順序上大於string2

string1 >= string2

string1在字母順序上大於等於string2

integer1 -eq integer2

integer1等於integer2

integer1 -ge integer2

integer1大於或等於integer2

integer1 -gt integer2

integer1大於integer2

integer1 -le integer2

integer1小於或等於integer2

integer1 -lt integer2

integer1小於integer2

integer1 -ne integer2

integer1不等於integer2

prefixinteger1 -pgt prefixinteger2

剔除非數字字元串prefix部分之後,integer1大於integer2

prefixinteger1 -plt prefixinteger2

剔除非數字字元串prefix部分之後,integer1小於integer2

file1 -nt file2

file1的修改時間比file2新

file1 -ot file2

file1的修改時間比file2舊

-d file

file存在且是目錄

-e file

file存在

-f file

file存在並且不是一個目錄

-s file

file存在並且文件占用空間大於零

-n string

string的長度大於零

string   

string的長度大於零,等價於-n string

-z string

string的長度等於零

( expression )

將expression作為一個整體

! expression  

非(NOT)

expression1 -a expression2

與(AND),也可以使用expression1 expression2,但不推薦

expression1 -o expression2

或(OR)

1.4.10 cat命令

讀取文件內容,藉此可以幫助判斷哪個是boot分區,哪個是根分區。

互動式命令行下使用。

1.4.11 clear命令

清屏。

1.4.12 configfile命令

立即裝載一個指定的文件作為grub的配置文件。但註意,導入的文件中的環境變數不在當前生效。

在grub.cfg丟失時,該命令將排上用場。

1.4.13 echo命令

echo [-n] [-e] string

"-n"和"-e"用法同shell中echo。如果要引用變數,使用${var}的方式。

1.4.14 export命令

導出環境變數,若在configfile的file中導出環境變數,將會在當前環境也生效。

1.4.15 halt和reboot命令

關機或重啟

1.4.16 ls命令

ls [args]

如果不給定任何參數,則列出grub可見的設備。

如果給定的參數是一個分區,則顯示該分區的文件系統信息。

如果給定的參數是一個絕對路徑表示的目錄,則顯示該目錄下的所有文件。

例如:

1.4.17 probe命令

probe [--set var] --partmap|--fs|--fs-uuid|--label device

探測分區或磁碟的屬性信息。如果未指定--set,則顯示指定設備對應的信息。如果指定了--set,則將對應信息的值賦給變數var。

--partmap:顯示是gpt還是mbr格式的磁碟。

--fs:顯示分區的文件系統。

--fs-uuid:顯示分區的uuid值。

--label:顯示分區的label值。

1.4.18 save_env和list_env命令

將環境變數保存到環境變數塊中,以及列出當前的環境變數塊中的變數。

1.4.19 loopback命令

loopback [-d] device file

將file映射為迴環設備。使用-d選項則是刪除映射。

例如:

loopback loop0 /path/to/image
ls (loop0)/

1.4.20 normal和normal_exit命令

進入和退出normal模式,normal是相對於救援模式而言的,只要不是在救援模式下,就是在normal模式下。

救援模式下,只能使用非常少的命令,而normal模式下則可以使用非常多的命令。

1.4.21 password和password_pbkdf2命令

password user clear-password
password_pbkdf2 user hashed-password

前者使用明文密碼定義一個名為user的用戶。不建議使用此命令。

後者使用哈希加密後的密碼定義一個名為user的用戶,加密的密碼通過"grub-mkpasswd-pbkdf2"工具生成。建議使用該命令。

1.5 幾個常設置的內置變數

1.5.1 chosen變數

當開機時選中某個菜單項啟動時,該菜單的title將被賦值給chosen變數。該變數一般只用於引用,而不用於修改。

1.5.2 cmdpath變數

grub2載入的core.img的目錄路徑,是絕對路徑,即包括了設備名的路徑,如(hd0,gpt1)/boot/grub2/。該變數值不應該修改。

1.5.3 default變數

指定預設的菜單項,一般其後都會跟隨timeout變數。

default指定預設菜單時,可使用菜單的title,也可以使用菜單的id,或者數值順序,當使用數值順序指定default時,從0開始計算。

1.5.4 timeout變數

設置菜單等待超時時間,設置為0時將直接啟動預設菜單項而不顯示菜單,設置為"-1"時將永久等待手動選擇。

1.5.5 fallback變數

當預設菜單項啟動失敗,則使用該變數指定的菜單項啟動,指定方式同default,可使用數值(從0開始計算)、title或id指定。

1.5.6 grub_platform變數

指定該平臺是"pc"還是"efi",pc表示的就是傳統的bios平臺。

該變數不應該被修改,而應該被引用,例如用於if判斷語句中。

1.5.7 prefix變數

在grub啟動的時候,grub自動將/boot/grub2目錄的絕對路徑賦值給該變數,使得以後可以直接從該變數所代表的目錄下載入各文件或模塊。

例如,可能自動設置為:

set prefix = (hd0,gpt1)/boot/grub2/

所以可以使用"$prefix/grubN.cfg"來引用/boot/grub2/grubN.cfg文件。

該變數不應該修改,且若手動設置,則必須設置正確,否則牽一發而動全身。

1.5.8 root變數

該變數指定根設備的名稱,使得後續使用從"/"開始的相對路徑引用文件時將從該root變數指定的路徑開始。一般該變數是grub啟動的時候由grub根據prefix變數設置而來的。

例如prefix=(hd0,gpt1)/boot/grub2,則root=(hd0,gpt1),後續就可以使用相對路徑/vmlinuz-XXX表示(hd0,gpt1)/vmlinuz-XXX文件。

註意:在Linux中,從根"/"開始的路徑表示絕對路徑,如/etc/fstab。但grub中,從"/"開始的表示相對路徑,其相對的基準是root變數設置的值,而使用"(dev_name)/"開始的路徑才表示絕對路徑。

一般root變數都表示/boot所在的分區,但這不是絕對的,如果設置為根文件系統所在分區,如root=(hd0,gpt2),則後續可以使用/etc/fstab來引用"(hd0,gpt2)/etc/fstab"文件。

該變數在grub2中一般不用修改,但若修改則必須指定正確。

另外,root變數還應該於linux或linux16命令所指定的內核啟動參數"root="區分開來,內核啟動參數中的"root="的意義是固定的,其指定的是根文件系統所在分區。例如:

set root='hd0,msdos1'

linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet LANG=en_US.UTF-8

initrd16 /initramfs-3.10.0-327.el7.x86_64.img

一般情況下,/boot都會單獨分區,所以root變數指定的根設備和root啟動參數所指定的根分區不是同一個分區,除非/boot不是單獨的分區,而是在根分區下的一個目錄。

1.6 grub配置和安裝示例

首先寫一個grub.cfg。例如此處,在msdos磁碟上安裝了兩個操作系統,CentOS 7和CentOS 6。

# 設置一些全局環境變數
set default=0
set fallback=1
set timeout=3

# 將可能使用到的模塊一次性裝載完
# 支持msdos的模塊
insmod part_msdos
# 支持各種文件系統的模塊
insmod exfat
insmod ext2
insmod xfs
insmod fat
insmod iso9660

# 定義菜單
menuentry 'CentOS 7' --unrestricted {
        search --no-floppy --fs-uuid --set=root 367d6a77-033b-4037-bbcb-416705ead095
        linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro biosdevname=0 net.ifnames=0 quiet
        initrd16 /initramfs-3.10.0-327.el7.x86_64.img
}
menuentry 'CentOS 6' --unrestricted {
        search --no-floppy --fs-uuid --set=root f5d8939c-4a04-4f47-a1bc-1b8cbabc4d32
        linux16 /vmlinuz-2.6.32-504.el6.x86_64 root=UUID=edb1bf15-9590-4195-aa11-6dac45c7f6f3 ro quiet
        initrd16 /initramfs-2.6.32-504.el6.x86_64.img
}

然後執行grub安裝操作。

shell> grub2-install /dev/sda

1.7 傳統grub簡述

因為本文主要介紹grub2,所以傳統的grub只簡單介紹下,其實前面已經提及了很多傳統grub和grub2的

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 包括初始化root用戶密碼password的過程以及兩個常見問題的解決方法 1. 下載MySQL zip包 進入 "MySQL官網" 按需選擇zip包下載並解壓, 比如現在我電腦裡面下載的是mysql 5.7.17 winx64 http://dev.mysql.com/downloads/mysq ...
  • 資料庫引擎接收到一個新的查詢請求(Batch或SP),查詢優化器會生成執行計劃,並緩存到記憶體中;下次再次執行相同的查詢請求時,資料庫引擎從復用已經緩存的執行計劃,換句話,資料庫引擎為每一個查詢請求生成執行計劃,並把已經生成的執行計劃緩存起來,當接收到相同的查詢請求時,資料庫引擎復用已緩存的執行計劃。 ...
  • Linux系統出現了性能問題,一般我們可以通過top、iostat、free、vmstat等命令來查看初步定位問題。在一個以前看到系統監控工具,總在想那些監控工具的代理,如何收集系統性能信息,io性能,cpu使用,帶寬使用等信息,偶然發現,不同系統均提供有性能分析工具的,代理可通過這些命令獲取系統性 ...
  • 1、簡介 2、read 3、運算工具 4、if/then結構 5、while迴圈 6、for迴圈 一、簡介 1、什麼是shell shell是用戶與系統交互作用的界面。shell是一種命令解釋程式,同時也是一種高級程式設計語言 2、shell常見種類 Bourne Shell(/usr/bin/sh ...
  • 1、輸入輸出,重定向,管道 2、<(cmd);>(cmd) 3、>;<;>>;<<;>>>;<<< 4、文本處理_1:cat;head;tail;cut;wc;sort;uniq;tr;tac;rev 一、輸入輸出,重定向,管道 1、Linux 程式有三個標準的輸入輸出,分別是: 標準輸入,用數字0 ...
  • 因為一些莫名其妙的原因重寫了三遍,燒壞了兩塊STC,十分心累 ...
  • " 1、關機命令(shutdown) " " 2、管理 Windows 服務(sc) " " 3、管理任務進程(tasklist、taskkill) " " 4、顯示 TCP/IP 配置值(ipconfig) " " 5、網路診斷工具(ping) " " 6、路由跟蹤工具(tracert) " " ...
  • KGTP 介紹 KGTP 是一個能在產品系統上實時分析 Linux 內核和應用程式(包括 Android)問題的全面動態跟蹤器。 使用 KGTP 不需要 在 Linux 內核上打 PATCH 或者重新編譯,只要編譯 KGTP 模塊並insmod 就可以。 其讓 Linux 內核提供一個遠程 GDB ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...