.. include:: ../disclaimer-zh_TW.rst

:Original: Documentation/admin-guide/sysrq.rst

:翻譯:

 黃軍華 Junhua Huang <huang.junhua@zte.com.cn>

:校譯:

 司延騰 Yanteng Si <siyanteng@loongson.cn>

.. _tw_admin-guide_sysrq:

Linux 魔法系統請求鍵駭客
========================

針對 sysrq.c 的文檔說明

什麼是魔法 SysRq 鍵？
~~~~~~~~~~~~~~~~~~~~~

它是一個你可以輸入的具有魔法般的組合鍵。
無論內核在做什麼，內核都會響應 SysRq 鍵的輸入，除非內核完全卡死。

如何使能魔法 SysRq 鍵？
~~~~~~~~~~~~~~~~~~~~~~~

在配置內核時，我們需要設置 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' 爲 'Y'。
當運行一個編譯進 sysrq 功能的內核時，/proc/sys/kernel/sysrq 控制着被
SysRq 鍵調用的功能許可。這個文件的默認值由 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE
配置符號設定，文件本身默認設置爲 1。以下是 /proc/sys/kernel/sysrq 中可能的
值列表：

   -  0 - 完全不使能 SysRq 鍵
   -  1 - 使能 SysRq 鍵的全部功能
   - >1 - 對於允許的 SysRq 鍵功能的比特掩碼（參見下面更詳細的功能描述）::

          2 =   0x2 - 使能對控制檯日誌記錄級別的控制
          4 =   0x4 - 使能對鍵盤的控制 (SAK, unraw)
          8 =   0x8 - 使能對進程的調試導出等
         16 =  0x10 - 使能同步命令
         32 =  0x20 - 使能重新掛載只讀
         64 =  0x40 - 使能對進程的信號操作 (term, kill, oom-kill)
        128 =  0x80 - 允許重啓、斷電
        256 = 0x100 - 允許讓所有實時任務變普通任務

你可以通過如下命令把值設置到這個文件中::

    echo "number" >/proc/sys/kernel/sysrq

這裏被寫入的 number 可以是 10 進制數，或者是帶着 0x 前綴的 16 進制數。
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 必須是以 16 進制數寫入。

注意，``/proc/sys/kernel/sysrq`` 的值隻影響通過鍵盤觸發 SySRq 的調用，對於
通過 ``/proc/sysrq-trigger`` 的任何操作調用都是允許的
（通過具有系統權限的用戶）。

如何使用魔法 SysRq 鍵？
~~~~~~~~~~~~~~~~~~~~~~~

在 x86 架構上
	你可以按下鍵盤組合鍵 `ALT-SysRq-<command key>`。

	.. note::
	   一些鍵盤可能沒有標識 'SySRq' 鍵。'SySRq' 鍵也被當做 'Print Screen'鍵。
	   同時有些鍵盤無法處理同時按下這麼多鍵，因此你可以先按下鍵盤 `Alt` 鍵，
	   然後按下鍵盤 `SysRq` 鍵，再釋放鍵盤 `SysRq` 鍵，之後按下鍵盤上命令鍵
	   `<command key>`，最後釋放所有鍵。

在 SPARC 架構上
	你可以按下鍵盤組合鍵 `ALT-STOP-<command key>` 。

在串行控制檯（只針對 PC 類型的標準串口）
        你可以發一個 ``BREAK`` ，然後在 5 秒內發送一個命令鍵，
	發送 ``BREAK`` 兩次將被翻譯爲一個正常的 BREAK 操作。

在 PowerPC 架構上
	按下鍵盤組合鍵 `ALT - Print Screen` （或者 `F13`） - `<命令鍵>` 。
        `Print Screen` （或者 `F13`） - `<命令鍵>` 或許也能實現。

在其他架構上
	如果你知道其他架構的組合鍵，請告訴我，我可以把它們添加到這部分。

在所有架構上
	寫一個字符到 /proc/sysrq-trigger 文件，例如::

		echo t > /proc/sysrq-trigger

這個命令鍵 `<command key>` 是區分大小寫的。

什麼是命令鍵？
~~~~~~~~~~~~~~

=========== ================================================================
命令鍵	    功能
=========== ================================================================
``b``	    將立即重啓系統，不會同步或者卸載磁盤。

``c``	    將執行系統 crash，如果配置了系統 crashdump，將執行 crashdump。

``d``	    顯示所有持有的鎖。

``e``	    發送 SIGTERM 信號給所有進程，除了 init 進程。

``f``	    將調用 oom killer 殺掉一個過度佔用內存的進程，如果什麼任務都沒殺，
            也不會 panic。

``g``	    kgdb 使用（內核調試器）。

``h``	    將會顯示幫助。（實際上除了這裏列舉的鍵，其他的都將顯示幫助，
	    但是 ``h`` 容易記住）:-)

``i``	    發送 SIGKILL 給所有進程，除了 init 進程。

``j``	    強制性的 “解凍它” - 用於被 FIFREEZE ioctl 操作凍住的文件系統。

``k``	    安全訪問祕鑰(SAK)殺掉在當前虛擬控制檯的所有程序，注意：參考
            下面 SAK 節重要論述。

``l``	    顯示所有活動 cpu 的棧回溯。

``m``	    將導出當前內存信息到你的控制檯。

``n``	    用於使所有實時任務變成普通任務。

``o``	    將關閉系統（如果配置和支持的話）。

``p``	    將導出當前寄存器和標誌位到控制檯。

``q``	    將導出每個 cpu 上所有已裝備的高精度定時器（不是完整的
            time_list 文件顯示的 timers）和所有時鐘事件設備的詳細信息。

``r``	    關閉鍵盤的原始模式，設置爲轉換模式。

``s``	    將嘗試同步所有的已掛載文件系統。

``t``	    將導出當前所有任務列表和它們的信息到控制檯。

``u``	    將嘗試重新掛載已掛載文件系統爲只讀。

``v``	    強制恢復幀緩存控制檯。
``v``	    觸發 ETM 緩存導出 [ARM 架構特有]

``w``	    導出處於不可中斷狀態（阻塞）的任務。

``x``	    在 ppc/powerpc 架構上用於 xmon 接口。
            在 sparc64 架構上用於顯示全局的 PMU（性能監控單元）寄存器。
            在 MIPS 架構上導出所有的 tlb 條目。

``y``	    顯示全局 cpu 寄存器 [SPARC-64 架構特有]

``z``	    導出 ftrace 緩存信息

``0``-``9`` 設置控制檯日誌級別，該級別控制什麼樣的內核信息將被打印到你的
	    控制檯。（比如 ``0`` ，將使得只有緊急信息，像 PANICs or OOPSes
	    才能到你的控制檯。）
=========== ================================================================

好了，我能用他們做什麼呢？
~~~~~~~~~~~~~~~~~~~~~~~~~~

嗯，當你的 X 服務端或者 svgalib 程序崩潰，unraw(r) 非原始模式命令鍵是非常
方便的。

sak(k)（安全訪問祕鑰）在你嘗試登陸的同時，又想確保當前控制檯沒有可以獲取你的
密碼的特洛伊木馬程序運行時是有用的。它會殺掉給定控制檯的所有程序，這樣你
就可以確認當前的登陸提示程序是實際來自 init 進程的程序，而不是某些特洛伊
木馬程序。

.. important::

   在其實際的形式中，在兼容 C2 安全標準的系統上，它不是一個真正的 SAK，
   它也不應該誤認爲此。

似乎其他人發現其可以作爲（系統終端聯機鍵）當你想退出一個程序，
同時不會讓你切換控制檯的方法。（比如，X 服務端或者 svgalib 程序）

``reboot(b)`` 是個好方法，當你不能關閉機器時，它等同於按下"復位"按鈕。

``crash(c)`` 可以用於手動觸發一個 crashdump，當系統卡住時。
注意當 crashdump 機制不可用時，這個只是觸發一個內核 crash。

``sync(s)`` 在拔掉可移動介質之前，或者在使用不提供優雅關機的
救援 shell 之後很方便 -- 它將確保你的數據被安全地寫入磁盤。注意，在你看到
屏幕上出現 "OK" 和 "Done" 之前，同步還沒有發生。

``umount(u)`` 可以用來標記文件系統正常卸載，從正在運行的系統角度來看，它們將
被重新掛載爲只讀。這個重新掛載動作直到你看到 "OK" 和 "Done" 信息出現在屏幕上
纔算完成。

日誌級別 ``0`` - ``9`` 用於當你的控制檯被大量的內核信息衝擊，你不想看見的時候。
選擇 ``0`` 將禁止除了最緊急的內核信息外的所有的內核信息輸出到控制檯。（但是如果
syslogd/klogd 進程是運行的，它們仍將被記錄。）

``term(e)`` 和 ``kill(i)`` 用於當你有些有點失控的進程，你無法通過其他方式殺掉
它們的時候，特別是它正在創建其他進程。

"just thaw ``it(j)`` " 用於當你的系統由於一個 FIFREEZE ioctl 調用而產生的文件
系統凍結，而導致的不響應時。

有的時候 SysRq 鍵在使用它之後，看起來像是“卡住”了，我能做些什麼？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

這也會發生在我這，我發現輕敲鍵盤兩側的 shift、alt 和 control 鍵，然後再次敲擊
一個無效的 SysRq 鍵序列可以解決問題。（比如，像鍵盤組合鍵 `alt-sysrq-z` ）
切換到另一個虛擬控制檯（鍵盤操作 `ALT+Fn` ），然後再切回來應該也有幫助。

我敲擊了 SysRq 鍵，但像是什麼都沒發生，發生了什麼錯誤？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

有一些鍵盤對於 SysRq 鍵設置了不同的鍵值，而不是提前定義的 99
(查看在 ``include/uapi/linux/input-event-codes.h`` 文件中 ``KEY_SYSRQ`` 的定義)
或者就根本沒有 SysRq 鍵。在這些場景下，執行 ``showkey -s`` 命令來找到一個合適
的掃描碼序列，然後使用 ``setkeycodes <sequence> 99`` 命令映射這個序列值到通用
的 SysRq 鍵編碼上（比如 ``setkeycodes e05b 99`` ）。最好將這個命令放在啓動腳本
中。
哦，順便說一句，你十秒鐘不輸入任何東西就將退出 “showkey”。

我想添加一個 SysRq 鍵事件到一個模塊中，如何去做呢？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

爲了註冊一個基礎函數到這個表中，首先你必須包含 ``include/linux/sysrq.h`` 頭
文件，這個頭文件定義了你所需要的所有東西。然後你必須創建一個 ``sysrq_key_op``
結構體，然後初始化它，使用如下內容，A） 你將使用的這個鍵的處理函數， B） 一個
help_msg 字符串，在 SysRq 鍵打印幫助信息時將打印出來，C） 一個 action_msg 字
符串，就在你的處理函數調用前打印出來。你的處理函數必須符合在 'sysrq.h' 文件中
的函數原型。

在 ``sysrq_key_op`` 結構體被創建後，你可以調用內核函數
``register_sysrq_key(int key, const struct sysrq_key_op *op_p);``，
該函數在表中的 'key' 對應位置內容是空的情況下，將通過 ``op_p`` 指針註冊這個操作
函數到表中 'key' 對應位置上。在模塊卸載的時候，你必須調用
``unregister_sysrq_key(int key, const struct sysrq_key_op *op_p)`` 函數，該函數
只有在當前該鍵對應的處理函數被註冊到了 'key' 對應位置時，纔會移除 'op_p' 指針
對應的鍵值操作函數。這是爲了防止在你註冊之後，該位置被改寫的情況。

魔法 SysRq 鍵系統的工作原理是將鍵對應操作函數註冊到鍵的操作查找表，
該表定義在 'drivers/tty/sysrq.c' 文件中。
該鍵表有許多在編譯時候就註冊進去的操作函數，但是是可變的。
並且有兩個函數作爲操作該表的接口被導出::

	register_sysrq_key 和 unregister_sysrq_key.

當然，永遠不要在表中留下無效指針，即，當你的模塊存在調用 register_sysrq_key()
函數，它一定要調用 unregister_sysrq_key() 來清除它使用過的 SysRq 鍵表條目。
表中的空指針是安全的。:)

如果對於某種原因，在 handle_sysrq 調用的處理函數中，你認爲有必要調用
handle_sysrq 函數時，你必須意識到當前你處於一個鎖中（你同時也處於一箇中斷處理
函數中，這意味着不能睡眠）。所以這時你必須使用 ``__handle_sysrq_nolock`` 替代。

當我敲擊一個 SysRq 組合鍵時，只有標題打印出現在控制檯？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SysRq 鍵的輸出和所有其他控制檯輸出一樣，受制於控制檯日誌級別控制。
這意味着，如果內核以發行版內核中常見的 "quiet" 方式啓動，則輸出可能不會出現在實際
的控制檯上，即使它會出現在 dmesg 緩存中，也可以通過 dmesg 命令和 ``/proc/kmsg``
文件的消費訪問到。作爲一個特例，來自 sysrq 命令的標題行將被傳遞給所有控制檯
使用者，就好像當前日誌級別是最大的一樣。如果只發出標題頭，則幾乎可以肯定內核日誌
級別太低。如果你需要控制檯上的輸出，那麼你將需要臨時提高控制檯日誌級別，通過使用
鍵盤組合鍵 `alt-sysrq-8` 或者::

    echo 8 > /proc/sysrq-trigger

在觸發了你感興趣的 SysRq 鍵命令後，記得恢復日誌級別到正常情況。

我有很多問題時，可以請教誰？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

請教在內核郵件列表上的人，郵箱：
	linux-kernel@vger.kernel.org

致謝
~~~~

- Mydraal <vulpyne@vulpyne.net> 撰寫了該文件
- Adam Sulmicki <adam@cfar.umd.edu> 進行了更新
- Jeremy M. Dolan <jmd@turbogeek.org> 在 2001/01/28 10:15:59 進行了更新
- Crutcher Dunnavant <crutcher+kernel@datastacks.com> 添加鍵註冊部分

