1. 程式人生 > >Linux下如何指定某一型別程式用特定程式開啟(通過binfmt_misc)

Linux下如何指定某一型別程式用特定程式開啟(通過binfmt_misc)

概述

在Windows平臺上,檔案系統中的檔案可以擁有特定的副檔名,系統根據不同的副檔名選擇使用特定的程式開啟。

在Linux平臺上,也提供了類似的功能,甚至從某種意義上來說更加的強大,只不過沒有windows那麼直觀那麼淺顯。Linux的核心從很早開始就引入了一個叫做Miscellaneous Binary Format(binfmt_misc)的機制,可以通過要開啟檔案的特性來選擇到底使用哪個程式來開啟,該機制根據檔案的元屬性來選擇合適的程式將其開啟。比Windows更加強大的地方是,它不光光可以通過檔案的副檔名來判斷,還可以通過檔案開始位置的特殊的位元組(Magic Byte),即檔案的元資料、檔案的格式頭來判斷。

binfmt_misc

  • 根據副檔名選擇程式開啟檔案
  • 根據檔案元屬性來選擇程式開啟檔案

如果要使用這個功能的話,首先要繫結binfmt_misc,可以通過以下命令來繫結:

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

這樣繫結的話,系統重新啟動之後就失效了。如果想讓系統每次啟動的時候都自動繫結的話,可以往/etc/fstab檔案中加入下面這行:

none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

繫結完之後,就可以通過向/proc/sys/fs/binfmt_misc/register(這個檔案只能寫不能讀)檔案中寫入一行匹配規則字串來告訴核心什麼樣的程式要用什麼樣的程式開啟(一般使用echo命令)。

這行字串的格式如下:

:name:type:offset:magic:mask:interpreter:flags

每個欄位都用冒號“:”分割。某些欄位擁有預設值,或者只在前面欄位被設定成了某個特定值後才有效,因此可以跳過某些欄位的設定,但是必須保留相應的冒號分割符。各個欄位的意義如下:

1)name:這個規則的名字,理論上可以取任何名字,只要不重名就可以了。但是為了方便以後維護一般都取一個有意義的名字,比如表示被開啟檔案特性的名字,或者要開啟這個檔案的程式的名字等;

2)type:表示如何匹配被開啟的檔案,只可以使用“E”或者“M”,只能選其一,兩者不可共用。“E”代表只根據待開啟檔案的副檔名來識別,而“M”表示只根據待開啟檔案特定位置的幾位魔數(Magic Byte)(==即檔案的元屬性,通過魔數來表示檔案的格式頭,可以用來識別檔案)==來識別;

3)offset:這個欄位只對前面type欄位設定成“M”之後才有效,它表示從檔案的多少偏移開始查詢要匹配的魔數。如果跳過這個字斷不設定的話,預設就是0;(因為不同平臺的檔案的魔數可能不是從同一個位置開始的,因此可以設定偏移值來從不同的位置去取得魔數

4)magic:它表示真正要匹配的魔數,如果type欄位設定成“M”的話;或者表示檔案的副檔名,如果type欄位設定成“E”的話。對於匹配魔數來說,如果要匹配的魔數是ASCII碼可見字元,可以直接輸入,而如果是不可見的話,可以輸入其16進位制數值,前面加上“\x”或者“\x”(如果在Shell環境中的話。對於匹配副檔名來說,就在這裡寫上檔案的副檔名,但不要包括副檔名前面的點號(“.”),且這個副檔名是大小寫敏感的,有些特殊的字元,例如目錄分隔符正斜槓(“/”)是不允許輸入的;

5)mask:同樣,這個欄位只對前面type欄位設定成“M”之後才有效。它表示要匹配哪些位,它的長度要和magic欄位魔數的長度一致。如果某一位為1,表示這一位必須要與magic對應的位匹配;如果對應的位為0,表示忽略對這一位的匹配,取什麼值都可以。如果是0xff的話,即表示全部位都要匹配,預設情況下,如果不設定這個欄位的話,表示要與magic全部匹配(即等效於所有都設定成0xff)。還有同樣對於NUL來說,要使用轉義(\x00),否則對這行字串的解釋將到NUL停止,後面的不再起作用;

6)interpreter:直譯器,表示要用哪個程式來啟動這個型別的檔案,一定要使用全路徑名,不要使用相對路徑名;

7)flags:這個欄位可選,主要用來控制interpreter開啟檔案的行為。比較常用的是‘P’(請注意,一定要大寫),表示保留原始的argv[0]引數。這是什麼意思呢?預設情況下,如果不設定這個標誌的話,binfmt_ misc會將傳給interpreter的第一個引數,即argv[0],修改成要被開啟檔案的全路徑名。當設定了‘P’之後,binfmt_misc會保留原來的argv[0],在原來的argv[0]和argv[1]之間插入一個引數,用來存放要被開啟檔案的全路徑名。比如,如果想用程式/bin/foo來開啟/usr/local/bin/blah這個檔案,如果不設定‘P’的話,傳給程式/bin/foo的引數列表argv[]是["/usr/local/bin/blah", “blah”],而如果設定了‘P’之後,程式/bin/foo得到的引數列表是["/bin/foo", “/usr/local/bin/blah”, “blah”]。

除了以上的規則之外,還有一些額外的限制條件:

1)每一行匹配規則字串的長度不能超過1920個字元;

2)魔數(Magic Byte)必須在檔案頭128個位元組內,也就是說offset+sizeof(magic)不能超過128;

3)interpreter欄位的長度不能超過127個字元。

如何判斷本機已經生效的檔案開啟規則

每次成功寫入一行規則,都會在/proc/sys/fs/binfmt_misc/目錄下,建立一個名字為輸入的匹配規則字串中"name"欄位的檔案。

通過讀取這個檔案的內容,可以知道這條匹配規則當前的狀態:

cat /proc/sys/fs/binfmt_misc/<name>

開關已有的規則

而通過向這個檔案中寫入0或1,可以關閉或開啟這條匹配規則,而寫入-1表示徹底刪除這條規則:

echo 0 > /proc/sys/fs/binfmt_misc/<name>    # Disable the match
echo 1 > /proc/sys/fs/binfmt_misc/<name>    # Enable the match
echo -1 > /proc/sys/fs/binfmt_misc/<name>   # Delete the match

確保具有root許可權寫入。

一鍵啟停bingmt_misc

在/proc/sys/fs/binfmt_misc/目錄下,還預設存在一個叫做status的檔案,通過它可以檢視和控制整個binfmt_misc的狀態,而不光是單個匹配規則。

檢視當前binfmt_misc是否處於開啟狀態:

cat /proc/sys/fs/binfmt_misc/status

也可以通過向它寫入1或0來開啟或關閉binfmt_misc:

echo 0 > /proc/sys/fs/binfmt_misc/status    # Disable binfmt_misc
echo 1 > /proc/sys/fs/binfmt_misc/status    # Enable binfmt_misc

如果想刪除當前binfmt_misc中的所有匹配規則,可以向其傳入-1:

echo -1 > /proc/sys/fs/binfmt_misc/status    # Disable all matches