啟動配置¶
- 作者:
Masami Hiramatsu <mhiramat@kernel.org>
概述¶
啟動配置擴充套件了當前的核心命令列,以支援在啟動核心時以有效的方式傳遞額外的鍵值資料。這允許管理員傳遞結構化的鍵配置 檔案。
配置檔案語法¶
啟動配置語法是一種簡單的結構化鍵值對。每個鍵由點連線的單片語成,鍵和值透過 = 連線。值必須以分號 (;) 或換行符 (\n) 結尾。對於陣列值,陣列條目用逗號 (,) 分隔。
KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
與核心命令列語法不同,逗號和 = 周圍允許空格。
每個關鍵字必須僅包含字母、數字、破折號 (-) 或下劃線 (_)。每個值只能包含可列印字元或空格,但分隔符除外,例如分號 (;)、換行符 (\n)、逗號 (,)、井號 (#) 和右括號 (})。
如果要在值中使用這些分隔符,可以使用雙引號 ("VALUE") 或單引號 ('VALUE') 將其引起來。請注意,您不能轉義這些引號。
可以存在沒有值或具有空值的鍵。這些鍵用於檢查鍵是否存在(類似於布林值)。
鍵值語法¶
啟動配置檔案語法允許使用者透過大括號合併部分相同的單詞鍵。例如
foo.bar.baz = value1
foo.bar.qux.quux = value2
這些也可以寫成
foo.bar {
baz = value1
qux.quux = value2
}
或者更簡潔地,寫成如下形式
foo.bar { baz = value1; qux.quux = value2 }
在這兩種樣式中,在啟動時解析時,相同的關鍵字會自動合併。因此,您可以追加類似的樹或鍵值對。
相同鍵的值¶
禁止兩個或多個值或陣列共享相同的鍵。例如,
foo = bar, baz
foo = qux # !ERROR! we can not re-define same key
如果要更新該值,則必須顯式使用覆蓋運算子 :=。例如
foo = bar, baz
foo := qux
然後,qux 被分配給 foo 鍵。這對於透過新增(部分)自定義啟動配置來覆蓋預設值而不解析預設啟動配置很有用。
如果要將該值作為陣列成員附加到現有鍵,可以使用 += 運算子。例如
foo = bar, baz
foo += qux
在這種情況下,鍵 foo 具有 bar、baz 和 qux。
此外,子鍵和一個值可以共存於父鍵下。例如,允許以下配置。
foo = value1
foo.bar = value2
foo := value3 # This will update foo's value.
請注意,由於沒有語法可以將原始值直接放在結構化鍵下,因此必須在括號外定義它。例如
foo {
bar = value1
bar {
baz = value2
qux = value3
}
}
此外,鍵下的值節點的順序是固定的。如果存在值和子鍵,則該值始終是鍵的第一個子節點。因此,如果使用者首先指定子鍵,例如
foo.bar = value1
foo = value2
在程式(和 /proc/bootconfig)中,它將顯示如下
foo = value2
foo.bar = value1
/proc/bootconfig¶
/proc/bootconfig 是啟動配置的使用者空間介面。與 /proc/cmdline 不同,此檔案顯示鍵值樣式列表。每個鍵值對都以以下樣式顯示在每一行中
KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...]
使用啟動配置啟動核心¶
有兩種使用啟動配置啟動核心的選項:將啟動配置附加到 initrd 映象或將其嵌入到核心本身中。
將啟動配置附加到 Initrd¶
由於預設情況下啟動配置檔案與 initrd 一起載入,因此它將新增到 initrd (initramfs) 映象檔案的末尾,並帶有填充、大小、校驗和和 12 位元組的魔術字,如下所示。
[initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
大小和校驗和欄位是無符號 32 位小端值。
當啟動配置新增到 initrd 映象時,總檔案大小將對齊到 4 位元組。為了填充間隙,將新增空字元 (\0)。因此,size 是啟動配置檔案 + 填充位元組的長度。
Linux 核心解碼記憶體中 initrd 映象的最後一部分以獲取啟動配置資料。由於這種“piggyback”方法,只要引導載入程式傳遞正確的 initrd 檔案大小,就無需更改或更新引導載入程式和核心映象本身。如果萬一引導載入程式傳遞了更大的大小,核心將無法找到啟動配置資料。
為了執行此操作,Linux 核心提供了 tools/bootconfig 下的 bootconfig 命令,該命令允許管理員將配置檔案應用或刪除到/從 initrd 映象。您可以使用以下命令構建它
# make -C tools/bootconfig
要將啟動配置檔案新增到 initrd 映象,請如下執行 bootconfig(如果存在舊資料,則會自動刪除)
# tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
要從映象中刪除配置,可以使用 -d 選項,如下所示
# tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
然後在正常的核心命令列上新增“bootconfig”,以告訴核心在 initrd 檔案的末尾查詢啟動配置。或者,構建核心時選擇 CONFIG_BOOT_CONFIG_FORCE Kconfig 選項。
將啟動配置嵌入到核心中¶
如果不能使用 initrd,也可以透過 Kconfig 選項將啟動配置檔案嵌入到核心中。在這種情況下,您需要使用以下配置重新編譯核心
CONFIG_BOOT_CONFIG_EMBED=y
CONFIG_BOOT_CONFIG_EMBED_FILE="/PATH/TO/BOOTCONFIG/FILE"
CONFIG_BOOT_CONFIG_EMBED_FILE 需要從原始碼樹或物件樹到啟動配置檔案的絕對路徑或相對路徑。核心將它嵌入為預設啟動配置。
就像將啟動配置附加到 initrd 一樣,您需要在核心命令列上使用 bootconfig 選項來啟用嵌入的啟動配置,或者,構建核心時選擇 CONFIG_BOOT_CONFIG_FORCE Kconfig 選項。
請注意,即使您設定了此選項,您也可以透過附加到 initrd 的另一個啟動配置來覆蓋嵌入的啟動配置。
透過啟動配置傳遞核心引數¶
除了核心命令列之外,啟動配置還可用於傳遞核心引數。 kernel 鍵下的所有鍵值對將直接傳遞到核心 cmdline。此外,init 下的鍵值對將透過 cmdline 傳遞給 init 程序。這些引數與使用者給定的核心 cmdline 字串連線在一起,順序如下,以便命令列引數可以覆蓋啟動配置引數(這取決於子系統如何處理引數,但通常,較早的引數將被後面的引數覆蓋。)
[bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params]
以下是核心/init 引數的啟動配置檔案示例。
kernel {
root = 01234567-89ab-cdef-0123-456789abcd
}
init {
splash
}
這將複製到核心 cmdline 字串中,如下所示
root="01234567-89ab-cdef-0123-456789abcd" -- splash
如果使用者給出一些其他命令列,例如,
ro bootconfig -- quiet
最終的核心 cmdline 將如下所示
root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet
配置檔案限制¶
目前,最大配置大小為 32KB,總關鍵字(不是鍵值條目)必須小於 1024 個節點。注意:這不是條目的數量而是節點,一個條目必須消耗超過 2 個節點(一個關鍵字和一個值)。因此理論上,它最多可以有 512 個鍵值對。如果鍵平均包含 3 個單詞,則它可以包含 256 個鍵值對。在大多數情況下,配置項的數量將少於 100 個條目並且小於 8KB,因此這將足夠了。如果節點數超過 1024,即使檔案大小小於 32KB,解析器也會返回錯誤。(請注意,此最大大小不包括填充空字元。)無論如何,由於 bootconfig 命令在將啟動配置附加到 initrd 映象時會驗證它,因此使用者可以在啟動前注意到它。
Bootconfig APIs¶
使用者可以查詢或迴圈遍歷鍵值對,也可以查詢根(字首)鍵節點並查詢該節點下的鍵值對。
如果您有一個鍵字串,您可以使用 xbc_find_value() 直接使用鍵查詢值。如果您想知道啟動配置中存在哪些鍵,可以使用 xbc_for_each_key_value() 迭代鍵值對。請注意,您需要使用 xbc_array_for_each_value() 來訪問每個陣列的值,例如
vnode = NULL;
xbc_find_value("key.word", &vnode);
if (vnode && xbc_node_is_array(vnode))
xbc_array_for_each_value(vnode, value) {
printk("%s ", value);
}
如果您想專注於具有字首字串的鍵,可以使用 xbc_find_node() 按字首字串查詢節點,並使用 xbc_node_for_each_key_value() 迭代字首節點下的鍵。
但最典型的用法是獲取字首下的命名值或獲取字首下的命名陣列,如下所示
root = xbc_find_node("key.prefix");
value = xbc_node_find_value(root, "option", &vnode);
...
xbc_node_for_each_array_value(root, "array-option", value, anode) {
...
}
這將訪問“key.prefix.option”的值和“key.prefix.array-option”的陣列。
不需要鎖定,因為初始化後,配置變為只讀。如果您需要修改,則必須複製所有資料和鍵。
函式和結構¶
-
uint32_t xbc_calc_checksum(void *data, uint32_t size)¶
計算啟動配置的校驗和
引數
void *data啟動配置資料。
uint32_t size啟動配置資料的大小。
描述
計算啟動配置資料的校驗和值。該校驗和將與 BOOTCONFIG_MAGIC 和大小一起用於將啟動配置嵌入到 initrd 映象中。
-
bool xbc_node_is_value(struct xbc_node *node)¶
測試節點是否為值節點
引數
struct xbc_node *node一個 XBC 節點。
描述
測試 node 是否為值節點,如果是值節點則返回 true,否則返回 false。
-
bool xbc_node_is_key(struct xbc_node *node)¶
測試節點是否為鍵節點
引數
struct xbc_node *node一個 XBC 節點。
描述
測試 node 是否為鍵節點,如果是鍵節點則返回 true,否則返回 false。
-
bool xbc_node_is_array(struct xbc_node *node)¶
測試節點是否為陣列值節點
引數
struct xbc_node *node一個 XBC 節點。
描述
測試 node 是否為陣列值節點。
-
bool xbc_node_is_leaf(struct xbc_node *node)¶
測試節點是否為葉鍵節點
引數
struct xbc_node *node一個 XBC 節點。
描述
測試 node 是否為葉鍵節點,即鍵節點並具有值節點或沒有子節點。 如果是葉節點則返回 true,否則返回 false。 請注意,除了值節點之外,葉節點還可以具有子鍵節點。
-
const char *xbc_find_value(const char *key, struct xbc_node **vnode)¶
查詢與鍵匹配的值
引數
const char *key搜尋鍵
struct xbc_node **vnodeXBC 值節點的容器指標。
描述
從整個 XBC 樹中搜索鍵與 key 匹配的值,如果找到則返回該值。找到的值節點儲存在 *vnode 中。請注意,對於僅鍵(非值)條目,這可以返回 0 長度的字串並在 *vnode 中儲存 NULL。
-
struct xbc_node *xbc_find_node(const char *key)¶
查詢與鍵匹配的節點
引數
const char *key搜尋鍵
描述
從整個 XBC 樹中搜索鍵與 key 匹配的(鍵)節點,如果找到則返回該節點。如果未找到,則返回 NULL。
-
struct xbc_node *xbc_node_get_subkey(struct xbc_node *node)¶
如果存在,則返回第一個子鍵節點
引數
struct xbc_node *node父節點
描述
返回 node 的第一個子鍵節點。如果 node 沒有子節點或只有值節點,則這將返回 NULL。
-
xbc_array_for_each_value¶
xbc_array_for_each_value (anode, value)
迭代陣列上的值節點
引數
anode一個 XBC 陣列值節點
value一個值
描述
迭代從 anode 開始的陣列值節點和值。 這應與 xbc_find_value() 和 xbc_node_find_value() 一起使用,以便使用者可以處理每個陣列條目節點。
-
xbc_node_for_each_child¶
xbc_node_for_each_child (parent, child)
迭代子節點
引數
parent一個 XBC 節點。
child迭代的 XBC 節點。
描述
迭代 parent 的子節點。每個子節點都儲存到 child。child 可以是值節點和子鍵節點的混合。
-
xbc_node_for_each_subkey¶
xbc_node_for_each_subkey (parent, child)
迭代子子鍵節點
引數
parent一個 XBC 節點。
child迭代的 XBC 節點。
描述
迭代 parent 的子鍵節點。每個子節點都儲存到 child。child 僅是子鍵節點。
-
xbc_node_for_each_array_value¶
xbc_node_for_each_array_value (node, key, anode, value)
迭代給定的鍵的陣列條目
引數
node一個 XBC 節點。
key在 node 下搜尋的鍵字串
anode陣列條目的迭代 XBC 節點。
value陣列條目的迭代值。
描述
迭代 node 下給定的 key 的陣列條目。 每個陣列條目節點都儲存到 anode 和 value。 如果 node 沒有 key 節點,則不執行任何操作。 請注意,即使找到的鍵節點只有一個值(不是陣列),也會執行一次塊。 但是,如果找到的鍵節點沒有值(僅鍵節點),則不執行任何操作。 因此,請勿使用它來測試鍵值對是否存在。
-
xbc_node_for_each_key_value¶
xbc_node_for_each_key_value (node, knode, value)
迭代節點下的鍵值對
引數
node一個 XBC 節點。
knode迭代的鍵節點
value迭代的值字串
描述
迭代 node 下的鍵值對。 每個鍵節點和值字串分別儲存在 knode 和 value 中。
-
xbc_for_each_key_value¶
xbc_for_each_key_value (knode, value)
迭代鍵值對
引數
knode迭代的鍵節點
value迭代的值字串
描述
迭代整個 XBC 樹中的鍵值對。每個鍵節點和值字串分別儲存在 knode 和 value 中。
-
int xbc_node_compose_key(struct xbc_node *node, char *buf, size_t size)¶
組合 XBC 節點的完整鍵字串
引數
struct xbc_node *node一個 XBC 節點。
char *buf用於儲存鍵的緩衝區。
size_t sizebuf 的大小。
描述
將 node 的完整鍵組合到 buf 中。返回儲存在 buf 中的鍵的總長度。如果 node 為 NULL,則返回 -EINVAL;如果鍵深度大於最大深度,則返回 -ERANGE。
-
int xbc_get_info(int *node_size, size_t *data_size)¶
獲取已載入的引導配置的資訊
引數
int *node_size用於儲存節點數量的指標。
size_t *data_size用於儲存引導配置資料大小的指標。
描述
如果 node_size 不為 NULL,則將其中的已使用節點數量儲存到 node_size 中;如果 data_size 不為 NULL,則將引導配置資料的大小儲存到 data_size 中。如果引導配置已初始化,則返回 0;否則返回 -ENODEV。
-
struct xbc_node *xbc_root_node(void)¶
獲取擴充套件引導配置的根節點
引數
void無引數
描述
返回擴充套件引導配置的根節點地址。如果擴充套件引導配置未初始化,則返回 NULL。
-
int xbc_node_index(struct xbc_node *node)¶
獲取 XBC 節點的索引
引數
struct xbc_node *node用於獲取索引的目標節點。
描述
返回 node 在 XBC 節點列表中的索引號。
-
struct xbc_node *xbc_node_get_parent(struct xbc_node *node)¶
獲取父 XBC 節點
引數
struct xbc_node *node一個 XBC 節點。
描述
返回 node 的父節點。如果該節點是樹的頂層節點,則返回 NULL。
-
struct xbc_node *xbc_node_get_child(struct xbc_node *node)¶
獲取子 XBC 節點
引數
struct xbc_node *node一個 XBC 節點。
描述
返回 node 的第一個子節點。如果該節點沒有子節點,則返回 NULL。
-
struct xbc_node *xbc_node_get_next(struct xbc_node *node)¶
獲取下一個兄弟 XBC 節點
引數
struct xbc_node *node一個 XBC 節點。
描述
返回 node 的下一個兄弟節點。如果該節點沒有下一個兄弟節點,則返回 NULL。請注意,即使此函式返回 NULL,也並不意味著 node 沒有兄弟節點。(您還需要檢查父節點的子節點是否為 node。)
-
const char *xbc_node_get_data(struct xbc_node *node)¶
獲取 XBC 節點的資料
引數
struct xbc_node *node一個 XBC 節點。
描述
返回 node 的資料(始終是以 null 結尾的字串)。如果該節點的資料無效,則發出警告並返回 NULL。
-
struct xbc_node *xbc_node_find_subkey(struct xbc_node *parent, const char *key)¶
查詢與給定鍵匹配的子鍵節點
引數
struct xbc_node *parent一個 XBC 節點。
const char *key鍵字串。
描述
在 parent 下搜尋與 key 匹配的鍵節點。key 可以包含多個用“.”連線的單詞。如果 parent 為 NULL,則從整棵樹搜尋節點。如果沒有匹配的節點,則返回 NULL。
-
const char *xbc_node_find_value(struct xbc_node *parent, const char *key, struct xbc_node **vnode)¶
查詢與給定鍵匹配的值節點
引數
struct xbc_node *parent一個 XBC 節點。
const char *key鍵字串。
struct xbc_node **vnode找到的 XBC 節點的容器指標。
描述
在 parent 下搜尋其(父)鍵節點與 key 匹配的值節點,將其儲存在 *vnode 中,並返回該值字串。key 可以包含多個用“.”連線的單詞。如果 parent 為 NULL,則從整棵樹搜尋節點。如果找到匹配的鍵,則返回該值字串;如果沒有匹配的節點,則返回 NULL。請注意,如果鍵沒有值,則此函式返回長度為 0 的字串,並在 *vnode 中儲存 NULL。此外,如果該值是一個數組,則它將返回第一個條目的值。
-
int xbc_node_compose_key_after(struct xbc_node *root, struct xbc_node *node, char *buf, size_t size)¶
組合 XBC 節點的部分鍵字串
引數
struct xbc_node *root根 XBC 節點
struct xbc_node *node目標 XBC 節點。
char *buf用於儲存鍵的緩衝區。
size_t sizebuf 的大小。
描述
將 node 的部分鍵組合到 buf 中,該部分鍵從 root 之後開始(不包括 root)。如果 root 為 NULL,則此函式返回 node 的完整鍵字。返回儲存在 buf 中的鍵的總長度。如果 node 為 NULL,或者 root 不是 node 的祖先,或者 root 是 node,則返回 -EINVAL;如果鍵深度大於最大深度,則返回 -ERANGE。此函式應與 xbc_find_node() 一起使用,以列出給定鍵下的所有(子)鍵。
-
struct xbc_node *xbc_node_find_next_leaf(struct xbc_node *root, struct xbc_node *node)¶
在給定節點下查詢下一個葉節點
引數
struct xbc_node *rootXBC 根節點
struct xbc_node *node開始查詢的 XBC 節點。
描述
在 root 節點下搜尋 node 的下一個葉節點(即終端鍵節點)(包括 root 節點本身)。如果找到下一個節點,則返回該節點;如果未找到下一個葉節點,則返回 NULL。
-
const char *xbc_node_find_next_key_value(struct xbc_node *root, struct xbc_node **leaf)¶
查詢下一個鍵值對節點
引數
struct xbc_node *rootXBC 根節點
struct xbc_node **leaf開始查詢的 XBC 節點的容器指標。
描述
在 root 節點下搜尋 *leaf 的下一個葉節點(即終端鍵節點)。如果找到下一個葉節點,則返回該值並更新 *leaf;如果未找到下一個葉節點,則返回 NULL。請注意,如果鍵沒有值,或者該值是一個數組,則此函式返回長度為 0 的字串,或第一個條目的值。
-
void _xbc_exit(bool early)¶
清除所有已解析的引導配置
引數
bool early如果是在 budy 系統初始化之前呼叫此函式,則設定為 true。
描述
此函式清除記憶體中已解析的引導配置的所有資料結構。如果需要使用新的引導配置重用 xbc_init(),則可以使用此函式。
-
int xbc_init(const char *data, size_t size, const char **emsg, int *epos)¶
解析給定的 XBC 檔案並構建 XBC 內部樹
引數
const char *data引導配置文字原始資料
size_t sizedata 的大小
const char **emsg用於儲存錯誤訊息的 const char * 指標
int *epos用於儲存錯誤位置的 int 指標
描述
此函式解析 data 中的引導配置文字。size 必須小於 XBC_DATA_MAX。如果成功,則返回儲存的節點數(>0);如果出現任何錯誤,則返回 -errno。在出錯的情況下,emsg 將更新為錯誤訊息,epos 將更新為錯誤位置,該錯誤位置是 buf 的位元組偏移量。如果該錯誤不是解析器錯誤,則 epos 將為 -1。
註釋¶
配置語法接受 shell 指令碼樣式的註釋。以井號 (“#”) 開頭直到換行符 (“\n”) 的註釋將被忽略。
# comment line foo = value # value is set to foo. bar = 1, # 1st element 2, # 2nd element 3 # 3rd element這將解析為如下
請注意,您不能在值和分隔符(
,或;)之間放置註釋。這意味著以下配置存在語法錯誤key = 1 # comment ,2