yassy's note

なんかかきます

コンソールタイプによってプロセスの環境変数LANGが変化する

※過去にまとめたwikiからの移行記事

Linuxの環境によってはコンソールタイプの違いにより、プロセスの環境変数LANGが変化することがある。
まずは、前提知識からおさらいしておく。

前提知識

標準入力に接続されているデバイス

Linuxではマシンにどのように接続したかによって端末デバイスが変わる。
例えば、マシンと物理的に接続されたキーボード・モニタから、あるいはコンソールでログインした場合の接続デバイスは/dev/ttyX(Xは数字)となる。

また、遠隔マシンにsshtelnetで接続した場合の接続デバイスは/dev/pts/X(Xは数字)となる。
自分がログインしている端末を確認するためには以下のコマンドを実行してみる。

> tty
/dev/pts/0

コンソールタイプ

consoletypeコマンドを実行した時に表示される接続デバイスの種類のこと。
以下のように表示される。

  • コンソールから実行
> consoletype
vt
> consoletype
pty

まとめると以下の通り。

接続方法 物理(もしくはコンソール)接続 SSH接続
端末デバイス /dev/ttyX /dev/pts/X
コンソールタイプ vt pts

本題

前提知識の話も終わったところで本題に入る。
先ほどのコンソールタイプの違いによっては、プロセスの環境変数LANGが変化してしまうのだ。
この問題は実際に見た方が早いので実験してみた。
なお、環境はCentOS6.10、ロケールはja_JP.UTF-8を設定している。

> cat /etc/sysconfig/i18n
LANG="ja_JP.UTF-8"

まずは、以下のように適当なプロセス(ここではrpcbind)の環境変数を見てみる。

> strings /proc/1521/environ
(略)
LANG=ja_JP.UTF-8
(略)

上記のように、rpcbindのLANGはja_JP.UTF-8となっている。
では、ここでコンソール端末からrpcbindサービスの再起動を行い、再度プロセスの環境変数を確認してみる。

> service rpcbind restart
rpcbind を停止中:                                          [  OK  ]
rpcbind を起動中:                                          [  OK  ]

> strings /proc/1230/environ
(略)
LANG=en_US.UTF-8
(略)

rpcbindのLANGがen_US.UTF-8に変化してしまっている。
では、今度はSSH端末からサービスの再起動を行ってみる。

> service rpcbind restart
rpcbind を停止中:                                          [  OK  ]
rpcbind を起動中:                                          [  OK  ]

> strings /proc/1560/environ
(略)
LANG=ja_JP.UTF-8
(略)

今度はja_JP.UTF-8に変化した。
最後にOS再起動を行った後のLANGを確認する。

> reboot
(再起動後)
> strings /proc/1226/environ
(略)
LANG=en_US.UTF-8
(略)

再起動後はen_US.UTF-8となった。
実験結果をまとめると以下の通り。

サービス起動方法 コンソール SSH OS再起動
LANG en_US.UTF-8 ja_JP.UTF-8 en_US.UTF-8

※なお、ロケールはja_JP.UTF-8

LANGが変化する理由

CentOS(RHEL)6系ではServiceコマンドで再起動、あるいはOS再起動を行うと、 /etc/profile.d/lang.shが呼ばれることで環境変数の設定が行われる。
このlang.shを見てみると、以下のようになっている。(長いので一部を抜粋)

if [ -n "$LANG" ]; then
    case $LANG in
    *.utf8*|*.UTF-8*)
    if [ "$TERM" = "linux" ]; then
            if [ "$consoletype" = "vt" ]; then
            case $LANG in
                ja*) LANG=en_US.UTF-8 ;;
                ko*) LANG=en_US.UTF-8 ;;
                si*) LANG=en_US.UTF-8 ;;
                zh*) LANG=en_US.UTF-8 ;;
                ar*) LANG=en_US.UTF-8 ;;
                fa*) LANG=en_US.UTF-8 ;;
                he*) LANG=en_US.UTF-8 ;;
                en_IN*) ;;
                *_IN*) LANG=en_US.UTF-8 ;;
            esac
        fi
    fi

lang.shではTERMが"linux"*1、consoletypeが“vt”の場合、LANGをen_US.UTF-8に設定する。

要するにコンソールでログインしている状態では、LANGがen_US.UTF-8となってしまうのだ。
そのため、いくら/etc/sysconfig/i18nロケールをja_JP.UTF-8に設定していても、 OS再起動時あるいはコンソールでのプロセス再起動時に、LANGがen_US.UTF-8となる。

SSH接続している場合には、lang.shの条件分岐に引っかからず(consoletypeがptsであるため)、 /etc/sysconfig/i18nで設定したロケール通りにja_JP.UTF-8となる。

なお、以上の問題はCUI環境で発生する問題であり、GUI環境では発生しない。
(GUI環境では$TERMがlinuxではなく、xtermとなるため)

*1:http://archive.linux.or.jp/JF/JFdocs/Text-Terminal-HOWTO-15.html によると、コンソール接続時における設定値。