x86_64ホストで、ネイティブモードでi686のプログラムをコンパイルしたい等の 場合、バーチャルマシンやコンテナを使わなくても i686 な chroot 環境があれば十分です。 ので、その準備方法。
$Keywords: i686 chroot, yum --installroot, rpm --root --initdb, --rebuilddb $
yum --disablerepo=\* --enablerepo=c7-media
に差し替えてください。
mkdir -p /chroot/i686 ## RPMデータベース (/var/lib/rpm/)を初期化 rpm --root /chroot/i686 --initdb ## yumのリポジトリ設定 (/etc/yum.repos.d/) を追加 rpm --root /chroot/i686 -ivh centos-release-7-3.1611.el7.centos.i686.rpm ## これでは.x86_64 のパッケージが選ばれてしまうので、 # yum --installroot=/chroot/i686 install rpm-build yum ## setarchで uname -m の値を変更して yum を起動する。 setarch i686 --32bit yum --installroot=/chroot/i686 install rpm-build yum sudo ## /etc/passwd を移植する。セキュリティ目的でchrootする場合は ## 丸コピーせず、必要最小限のアカウントに絞ったほうが良い cp -p /etc/{group,gshadow,passwd,shadow} /chroot/i686/etc/ cp -p /etc/sudoers /chroot/i686/etc/ ## (nsswitch.conf で/etc/passwd以外を使うのなら、NSS関連ファイルも移植する) ## chroot内から外部ネットワークのDNS解決をできるようにする cp -p /etc/resolv.conf /chroot/i686/etc/ ## ここまで、1回やればよい設定
## ここから、再起動したらやり直す設定 ## mount は、ホストの /etc/fstab に書いておけば自動マウントさせることもできる mount -t proc -o nosuid,nodev,noexec proc /chroot/i686/proc mount -t devtmpfs -o nosuid,strictatime devmpfs /chroot/i686/dev mount -t devpts -o nosuid,noexec,gid=5,mode=620 devpts /chroot/i686/dev/pts ;# for sshd mount --bind /home /chroot/i686/home ;# セキュリテイ目的の場合は行わない
#------- #/etc/fstab に固定するなら、以下のように書く /proc /chroot/i686/proc auto bind 0 0 /dev /chroot/i686/dev auto bind 0 0 /dev/pts /chroot/i686/dev/pts auto bind 0 0 /home /chroot/i686/home auto bind 0 0 #-------
host$ sudo setarch i686 --32bit chroot /chroot/i686 bash-4.2# uname -a Linux TSPC330-VM1 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 i686 i686 i386 GNU/Linux bash-4.2# _「カーネルは x86_64 だが、ユーザーランドは全部 i686」な環境です。 glibc なんかはクロスコンパイル状態ではうまくコンパイルできませんが、 この chroot な環境ならコンパイルできます。
chroot環境を使うたびに毎回
sudo setarch i686 --32bit chroot /chroot/i686 sudo -u $LOGNAME -s
するのはだるいので、chroot内で sshd を動かします。
## ホスト側から sshd をインストールする setarch i686 --32bit yum --installroot=/chroot/i686 install openssh-server ## ホストの ssh key を移植する cp -p --preserve=all /etc/ssh/ssh_host* /chroot/i686/etc/ssh/ ## ポート番号を変える。LXCやVMではないので、ネットワークはホストと共用のため vi /chroot/i686/etc/ssh/sshd_config ;# Port 6022 などに変える ## chroot内のsshdを動かす setarch i686 --32bit chroot /chroot/i686 /usr/sbin/sshd ## pidは /chroot/i686/var/run/sshd.pid に残る ## なお、chroot内では systemd関連コマンドは使えない。 ## (/ と /proc/1/root の st_ino が違うと動作を拒否される)
chroot環境で作業しているかどうかを判断する手段は意外に無いので、 プロンプトを変えてみます。 hostnameなどはホストと共用なのでアテにならない。 chroot側の ~/.bashrc に書き加えます:
# ~/.bashrc #... ROOTINO=`stat -c %i /` if [ "$ROOTINO" != 2 ]; then PS1="[\u@\h-$ROOTINO \W]\$ " fi/ の inode が 2 以外であれば chroot環境なので、その値を PS1 に追加してみます。 あまり美しくありません。 具体的に chroot しているパス名を chroot環境下で取得する方法は無いようです というかできたらたぶんセキュリティーホール。
chroot環境を複数使う場合は、echo /chroot/i686 > /chroot/i686/etc/chrooted のような目印になるファイルを作って読み込んだほうが良いでしょう。
/etc/systemd/system/chroot-sshd@.service
として
作成してから、
# # systemctl enable chroot-sshd@chrootdir-i686:6022.service # systemctl start chroot-sshd@chrootdir-i686:6022.service # -> invokes chroot /chrootdir/i686 sshd -p 6022 # [Unit] Description=chrooted OpenSSH server daemon Documentation=man:sshd(8) man:sshd_config(5) After=network.target sshd-keygen.service Wants=sshd-keygen.service [Service] Type=simple EnvironmentFile=/etc/sysconfig/sshd ExecStart=/bin/sh -c 'UNIT_I="%I"; d=/$${UNIT_I%:*}; if [ ! -d $$d ]; then echo $$d nonexistent; exit 1; fi; case "$$UNIT_I" in *:[0-9]*) p="-p $${UNIT_I#*:}"; esac; exec setarch i686 --32bit chroot $$d /usr/sbin/sshd -D $$p $OPTIONS' ExecReload=/bin/kill -HUP $MAINPID KillMode=process #Restart=on-failure #RestartSec=42s [Install] WantedBy=multi-user.target
sudo systemctl enable chroot-sshd@chroot-i686.service ;#自動起動の設定 sudo systemctl start chroot-sshd@chroot-i686.service ;#起動する sudo systemctl status chroot-sshd@chroot-i686.service ;#状況確認
chroot内では systemd は動かせないので、 プロセス管理はホスト側でやることになります。
sshd -D でフォアグラウンド起動しているので、PidFileの設定はありません。
ここまでやるなら、chroot先の特殊mountは /etc/fstab ではなく 専用の systemd unit (chroot-mount@.serviceとか) を作りたくなりますが、 本稿はそこまではやりません。
host$ sudo yum --installroot=/chroot/i686 install sudo error: db5 error(5) from dbenv->open: Input/output error error: cannot open Packages index using db5 - Input/output error (5) error: cannot open Packages database in /chroot/i686/var/lib/rpm CRITICAL:yum.main: Error: rpmdb open failed
不思議なことに chroot 内から yum を起動するとまだ使えたりする。
対処法:
host$ sudo rpm --root=/chroot/i686 -v --rebuilddb原因はよくわかりませんが、たまにホスト側から見ると /var/lib/rpm/ の Berkeley DBが壊れているように見えることがあるようです。
test_ioctl test_ioctl (test.test_ioctl.IoctlTests) ... ok test_ioctl_mutate (test.test_ioctl.IoctlTests) ... ok test_ioctl_mutate_1024 (test.test_ioctl.IoctlTests) ... ok test_ioctl_mutate_2048 (test.test_ioctl.IoctlTests) ... ok test_ioctl_signed_unsigned_code_param (test.test_ioctl.IoctlTests) ... test test_ioctl failed -- Traceback (most recent call last): File "/home/kabe/python-c7/BUILD/Python-2.7.5/Lib/test/test_ioctl.py", line 71, in test_ioctl_signed_unsigned_code_param mfd, sfd = pty.openpty() File "/home/kabe/python-c7/BUILD/Python-2.7.5/Lib/pty.py", line 29, in openpty master_fd, slave_name = _open_terminal() File "/home/kabe/python-c7/BUILD/Python-2.7.5/Lib/pty.py", line 70, in _open_terminal raise os.error, 'out of pty devices' OSError: out of pty devices ERROR ====================================================================== ERROR: test_ioctl_signed_unsigned_code_param (test.test_ioctl.IoctlTests) ----------------------------------------------------------------------
対処: /proc, /dev, /dev/pts のマウントオプションを 確認してください。 nosuidやらstrictatimeやらが必要なものがあります。 「正しい」オプションでマウントされていれば、test_ioctlは スキップされます(解決になってない)。
$ script typescript script: openpty failed: Operation not permitted Terminated
対処: /dev/pts のマウントオプションに
gid=5
がついているか確認します。
/etc/fstab に bind マウントでなく、ベタ書きで
devpts /chroot/i686/dev/pts devpts nosuid,noexec 0 0と書いて
gid=5
を忘れると、
ホスト側の /dev/pts のマウントオプションも道連れで変更され、
root以外では openpty(3) (grantpt(3)) が正常に動かなくなります。
解説: glibc は、openpty(3) で仮想端末を割り当てる際、 マスター側は /dev/ptmx をオープンし、 スレーブ側はchown $LOGNAME tty /dev/pts/0 相当のことを行います。 が、/dev/pts が gid=5 (tty) 無しでマウントされていると、スレーブ側は st_uid, st_gid がユーザーのものになっていて ttyグループではなくなるため、 chown が失敗します (root以外では)。