想在 chroot 環境下使用中文輸入法, 要滿足以下條件

  1. host & chroot 環境都使用相同的輸入法
  2. 使用跟 host 相同的 UID 執行程序
  3. Bind mount 輸入法會用到的 socket 到 chroot 環境中
  4. 在 chroot 環境中設定以下變量
    • XMODIFIERS
    • GTK_IM_MODULE
    • QT_IM_MODULE
    • QT4_IM_MODULE
  5. 當然, chroot 環境中的 X client 必須要能正常的跟 X server 溝通.

下面用我常用的 scim 為例, 新的 root 位置在 ~/newroot.

host & chroot 環境都使用相同的輸入法

在 chroot 環境下安裝 scim

$ sudo chroot ~/newroot apt-get install scim scim-tables-zh

使用跟 host 相同的 UID 執行程序

最簡單的作法是將 host 的 /etc/passwd, /etc/group bind mount 到 chroot 環境中

$ sudo mount --bind /etc/passwd ~/newroot/etc/passwd
$ sudo mount --bind /etc/group ~/newroot/etc/group

執行應用時通常會在 $HOME 中讀/寫資料, 如果 $HOME 沒準備好, 或是無法寫入, 通常會造成程序執行出問題.

一種解法是將 host 的 $HOME 直接 bind mount 到 chroot 環境中

$ sudo mkdir ~/newroot$HOME
$ sudo mount --bind $HOME ~/newroot$HOME

或者, 在 chroot 環境中建個空目錄即可

$ sudo mkdir ~/newroot$HOME
$ sudo chown $USER:$USER ~/newroot$HOME

Bind mount 輸入法會用到的 socket 到 chroot 環境中

先瞭解下 scim 是怎麼通訊的

$ pgrep scim | while read pid; do ls /proc/$pid/fd -l; done                                                                              [19/2699]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20717]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[19802]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[19803]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[19807]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 7 -> socket:[21661]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 8 -> socket:[21662]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20722]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[20723]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[16316]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[19834]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 7 -> socket:[20769]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 10 -> socket:[16321]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 11 -> socket:[19827]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 12 -> anon_inode:[eventfd]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 13 -> socket:[19048]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 14 -> socket:[19049]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 15 -> socket:[19836]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 17 -> socket:[20137]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20722]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[20723]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[16316]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[16318]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 7 -> socket:[16320]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 8 -> anon_inode:[eventfd]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 9 -> anon_inode:[eventfd]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20722]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[20723]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[16312]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[16337]
$ pgrep scim | while read pid; do ls /proc/$pid/fd -l; done                                                                              [19/2699]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20717]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[19802]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[19803]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[19807]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 7 -> socket:[21661]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 8 -> socket:[21662]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20722]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[20723]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[16316]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[19834]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 7 -> socket:[20769]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 10 -> socket:[16321]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 11 -> socket:[19827]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 12 -> anon_inode:[eventfd]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 13 -> socket:[19048]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 14 -> socket:[19049]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 15 -> socket:[19836]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 17 -> socket:[20137]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20722]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[20723]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[16316]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[16318]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 7 -> socket:[16320]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 8 -> anon_inode:[eventfd]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 9 -> anon_inode:[eventfd]
total 0
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 0 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 1 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 2 -> /dev/null
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 3 -> socket:[20722]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 4 -> socket:[20723]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 5 -> socket:[16312]
lrwx------ 1 derekdai derekdai 64 Nov 17 19:43 6 -> socket:[16337]

看起來是以 socket 進行通訊的, 看看 socket file 放在什麼地方

netstat -axp | grep scim
unix  2      [ ACC ]     STREAM     LISTENING     21096    1695/scim-im-agent  /tmp/[email protected]:0.0
unix  2      [ ACC ]     STREAM     LISTENING     19049    1510/scim-panel-gtk /tmp/scim-panel-socket:0-derekdai
unix  2      [ ACC ]     STREAM     LISTENING     19834    1509/scim-helper-ma /tmp/scim-helper-manager-socket-derekdai
unix  2      [ ACC ]     STREAM     LISTENING     20717    1488/scim-launcher  /tmp/scim-socket-frontend-derekdai
unix  3      [ ]         STREAM     CONNECTED     16337    1512/scim-launcher  
unix  3      [ ]         STREAM     CONNECTED     16316    1509/scim-helper-ma 
unix  3      [ ]         STREAM     CONNECTED     31716    1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     19802    1488/scim-launcher  /tmp/scim-socket-frontend-derekdai
unix  3      [ ]         STREAM     CONNECTED     21847    1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     19048    1510/scim-panel-gtk 
unix  3      [ ]         STREAM     CONNECTED     21110    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     21109    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     19409    1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     21662    1488/scim-launcher  /tmp/scim-socket-frontend-derekdai
unix  3      [ ]         STREAM     CONNECTED     20134    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     16318    1510/scim-panel-gtk 
unix  3      [ ]         STREAM     CONNECTED     16321    1510/scim-panel-gtk 
unix  3      [ ]         STREAM     CONNECTED     21106    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     19836    1510/scim-panel-gtk /tmp/scim-panel-socket:0-derekdai
unix  3      [ ]         STREAM     CONNECTED     16320    1510/scim-panel-gtk 
unix  3      [ ]         STREAM     CONNECTED     141301   1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     20722    1509/scim-helper-ma 
unix  3      [ ]         STREAM     CONNECTED     21111    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     19803    1488/scim-launcher  /tmp/scim-socket-frontend-derekdai
unix  3      [ ]         STREAM     CONNECTED     20137    1510/scim-panel-gtk /tmp/scim-panel-socket:0-derekdai
unix  3      [ ]         STREAM     CONNECTED     19827    1510/scim-panel-gtk 
unix  3      [ ]         STREAM     CONNECTED     20135    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     22532    1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     145593   1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     21661    1488/scim-launcher  /tmp/scim-socket-frontend-derekdai
unix  3      [ ]         STREAM     CONNECTED     23600    1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     109818   1695/scim-im-agent  /tmp/[email protected]:0.0
unix  3      [ ]         STREAM     CONNECTED     19807    1488/scim-launcher  /tmp/scim-socket-frontend-derekdai
unix  3      [ ]         STREAM     CONNECTED     16312    1512/scim-launcher  
unix  3      [ ]         STREAM     CONNECTED     21107    1695/scim-im-agent  
unix  3      [ ]         STREAM     CONNECTED     20723    1509/scim-helper-ma 
unix  3      [ ]         STREAM     CONNECTED     20769    1509/scim-helper-ma /tmp/scim-helper-manager-socket-derekdai
unix  2      [ ]         STREAM                   21656    1695/scim-im-agent

看起來 socket file 都在 /tmp

$ ls /tmp/ -l | grep scim
srw------- 1 derekdai derekdai    0 Nov 17 17:02 scim-helper-manager-socket-derekdai
srwxr-xr-x 1 derekdai derekdai    0 Nov 17 17:02 [email protected]:0.0
srw------- 1 derekdai derekdai    0 Nov 17 17:02 scim-panel-socket:0-derekdai
srw------- 1 derekdai derekdai    0 Nov 17 17:02 scim-socket-frontend-derekdai

所以只要將 /tmp bind mount 到 chroot 環境即可.

$ sudo mount --bind /tmp ~/newroot/tmp

在 chroot 環境中設定變量

先 chroot 進新 root, 並切換身份, 成為跟 host 一樣的 user

$ sudo chroot ~/newroot su - $USER

可以 export 以下變量, 並執行程序 (例如 gedit)

$ export [email protected]=SCIM
$ export GTK_IM_MODULE=scim
$ export QT4_IM_MODULE=scim

或是這麼執行

$ [email protected]=SCIM \
 GTK_IM_MODULE=scim \
 QT4_IM_MODULE=scim \
 gedit

Enjoy your input method!