目前是 LikeCoin Chain 验证人 Yoitsu 背后的家伙,以及 CDC/CFC 划水组成员(笑)。偶尔会变身成狐狸。( @foobarz )
在 Android 上创建 GNU/Linux 容器
那这次再说吧……
再一次提醒没有耐心和同理心的家伙们去用其它即用的工具像是 TermuxArch 和 Linux Deploy ……
所以这回咱们要干什么?
由于咱不可能把所有发行版都装一次,也不可能在各种手机上都测试一遍,于是咱只能拿 咱手边的家伙举个例子,例如咱手上的小米平板4 ……
- 一部 aarch64 / arm64 设备
现在的手机 CPU 基本上都是 64 位了吧,不知道的话搜索一下手上 CPU 的型号应该就能看个大概。
- 比较新的 Android 系统,最好有 root 权限和完整 busybox 支持。
如果汝已经动手给手机安装了第三方 ROM,那应该不是什么难事。 某蓝绿海厂等受害者可以尝试 UserLAnd……
- 一些剩余存储空间 (这不是废话么)
- 安装好终端模拟器和合适的键盘。
或者 Termux 也可以,在里面装上 tsu 以后可以让 Termux 里的 Bash 以 root 用户运行。
作为好几年的 Arch Linux 受害 爱好者,咱当然就装一个 ArchLinux ARM 试试看啦 (虽然这不是官方分支,以及不是有 TermuxArch 了么……)
那么我们的目标是,没有蛀牙 ……
- 能够在 chroot 下基本正常工作
例如正常的使用包管理器、安装软件以及用它们等等。
- 能够访问网络和内存设备 (踩坑警告)
- 能够通过外部访问 (ssh 或者 vnc 啥的)
如有任何不适还请装作没事
天降大坑 nosuid ……(?)
某些手机上的 /data 挂载的时候加上了 nosuid 选项,于是 sudo 就炸了……
sudo: effective uid is not 0, is /sbin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
这种情况可以考虑创建一个磁盘映像把容器放进去(大概吧……)
# 找个地方创建一个映像文件 dd if=/dev/zero of=/path/to/root.img bs=1048576 count=4096 # 给映像创建文件系统和挂载 mke2fs -t ext4 -F /path/to/root.img mkdir -p /data/linux/arch mount -t ext4 -o loop /path/to/root.img /data/linux/arch
如果肯定不用 sudo 的话能不能当做没事……
要有空间,于是……
丢了个 tarball 下来让汝自己 bootstrap 去(啥?)
安装 GNU/Linux 发行版的过程,其实就是在解决一个先有鸡还是先有蛋的问题,这个过程就是 bootstrap。 大概就是……
- 从别的什么可以启动的地方把要安装的 GNU/Linux 发行版的最小的部份下载回来,安装上。
- 通过一些方法进入这个最小的部份中(例如 chroot ),为目标设备特化配置。
只不过大部分发行版的安装过程中被自动化了(Arch / Gentoo 等用户表示情绪稳定。)。 在 Android 上安装,同样要经过这个过程。
于是,首先咱们要下载 Arch Linux ARM 的 tarball ,可以在电脑上下载下来发送到手机上,也可以用手机 的浏览器直接下载,也可以用 curl 或者 wget:
wget http://os.archlinuxarm.org/os/ArchLinuxARM-aarch64-latest.tar.gz
如果直接从官方仓库下载不够快的话,可以通过镜像网站下载,例如:
https://mirrors.tuna.tsinghua.edu.cn/archlinuxarm/os/ArchLinuxARM-aarch64-latest.tar.gz
然后创建一个目录存放解压出来的基本系统,再解压出来刚下载的 tarball:
# 因为 SD 卡可能放不下权限等神奇的原因,就放在内存设备上好了…… # mkdir -p /data/linux/arch # 以及 Arch Linux ARM 官方是建议用 bsdtar 的,要是汝的手机上凑巧有(不管是 # 系统里的还是 Termux 的),就用上吧…… # bsdtar -xpf /path/to/ArchLinuxARM-aarch64-latest.tar.gz -C /path/to/mountpoint # 不然 tar 也是可以的。 # tar -xzvf /path/to/ArchLinuxARM-aarch64-latest.tar.gz -C /path/to/mountpoint
Chroot on Android
在普通的 GNU/Linux 发行版上 chroot 时,咱们大抵会这么做:
# 切换到 chroot 的目标目录并挂载上 /dev /sys 这样的伪文件系统 # cd /location/of/new/root # mount -t proc proc proc/ # mount --rbind /sys sys/ # mount --rbind /dev dev/ # 通过给定的 shell 进入 chroot # chroot /location/of/new/root /bin/bash
在 Android 上其实也差不多:
# mount -o bind /dev /data/linux/arch # mount -o bind /sys /data/linux/arch/sys # mount -o bind /proc /data/linux/arch/proc # mount -t tmpfs tmpfs /data/linux/arch/tmp
以及记得修改一下 chroot 里面的 /etc/resolv.conf , Arch 这个默认是到 /run/systemd/resolve/resolv.conf 的软链接。 反正里面也没有 systemd 用 ,于是 删掉重建好了……
# /data/linux/arch/etc/resolv.conf nameserver 8.8.8.8 nameserver 8.8.4.4
如果有必要的话,可以同时修改里面的镜像仓库地址。
# /data/linux/arch/etc/pacman.d/mirrorlist Server = https://mirrors.ustc.edu.cn/archlinuxarm/$arch/$repo
然后就和平常一样 chroot 进去咯~
clover:/data/linux # chroot /data/linux/arch /bin/bash [root@localhost /]#
起始配置
The bootstrap environment is really barebones (no nano or lvm2). Therefore, we need to set up pacman in order to download other necessary packages.
这下知道为啥要在外面改 /etc/resolv.conf 了吧(当然汝要是独辟蹊径的话那当咱没说……)
正如 官方说明提示的一样 ,初始化 pacman 密钥环和获得密钥:
[root@localhost /]# pacman-key --init gpg: /etc/pacman.d/gnupg/trustdb.gpg: trustdb created gpg: no ultimately trusted keys found gpg: starting migration from earlier GnuPG versions gpg: porting secret keys from '/etc/pacman.d/gnupg/secring.gpg' to gpg-agent gpg: migration succeeded gpg: Generating pacman keyring master key... gpg: key 56753AA14274D5A7 marked as ultimately trusted gpg: directory '/etc/pacman.d/gnupg/openpgp-revocs.d' created gpg: revocation certificate stored as '/etc/pacman.d/gnupg/openpgp-revocs.d/46C9147EE071F7E5D16A085856753AA14274D5A7.rev' gpg: Done ==> Updating trust database... gpg: marginals needed: 3 completes needed: 1 trust model: pgp gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u [root@localhost /]# pacman-key --populate archlinuxarm ==> Appending keys from archlinuxarm.gpg... ==> Locally signing trusted keys in keyring... -> Locally signing key 69DD6C8FD314223E14362848BF7EEF7A9C6B5765... -> Locally signing key 02922214DE8981D14DC2ACABBC704E86B823CD25... -> Locally signing key 9D22B7BB678DC056B1F7723CB55C5315DCD9EE1A... ==> Importing owner trust values... gpg: setting ownertrust to 4 gpg: inserting ownertrust of 4 gpg: setting ownertrust to 4 ==> Updating trust database... gpg: marginals needed: 3 completes needed: 1 trust model: pgp gpg: depth: 0 valid: 1 signed: 3 trust: 0-, 0q, 0n, 0m, 0f, 1u gpg: depth: 1 valid: 3 signed: 1 trust: 0-, 0q, 0n, 3m, 0f, 0u gpg: depth: 2 valid: 1 signed: 0 trust: 1-, 0q, 0n, 0m, 0f, 0u [root@localhost /]#
接下来安装(和更新)基本系统,如果有别的需要的话也可以装别的。
[root@localhost /]# pacman -Syu base base-devel nano --needed
如果不幸遇到了像是 error: could not determine cachedir mount point /var/cache/pacman/pkg 这样的错误, 那在 /etc/pacman.conf 里把 Misc options 下面的 CheckSpace 注释掉应该能绕过 (于是有别的方法嘛)
基于正经的 GNU/Linux 用户不会日用 root 账户这一指导原则(啥?),咱们也要新建一个用户:
[root@localhost /]# useradd -m -s /bin/bash horo [root@localhost /]# passwd horo
有必要的话也可以修改 sudoers 文件(记得用 visudo),把汝刚刚创建的用户添加到 sudoers 中。
以及介于 Android 的魔改属性,只有特定的组可以进行像是访问网络或者访问 SD 卡等操作,于是 还要在 chroot 里新建相应的组,并把新建的用户加到这些组去:
# groupadd 可以用 -g 参数制定新增组的 id ,至于这些组分别是啥 # 看后面的组名应该就知道了吧…… groupadd -g 3001 android_bt groupadd -g 3002 android_bt-net groupadd -g 3003 android_inet groupadd -g 3004 android_net-raw groupadd -g 1015 sdcard-rw groupadd -g 1028 sdcard-r # 然后把新建的用户添加到合适的组中 gpasswd -a horo android_bt gpasswd -a horo android_bt-net gpasswd -a horo android_inet gpasswd -a horo android_net-raw gpasswd -a horo sdcard-rw gpasswd -a horo sdcard-r
最后(?),因为没有 systemd,所以请像新装 Arch Linux 的时候一样手动设置一下 locales:
- /etc/locale.gen 是一个仅包含注释文档的文本文件。指定您需要的本地化类型,去掉对应行前面的注释符号(#)就可以啦,还是用 nano 打开,建议选择帶UTF-8的項:
# nano /etc/locale.gen en_US.UTF-8 UTF-8
- 执行 locale-gen 以生成 locale 讯息:
# locale-gen
- 创建 locale.conf 并提交本地化选项:
# echo 用来输出某些文字,后面的大于号表示把输出保存到某个文件里啦~ # 或者可以用文字编辑器新建这个文件加上这一行。 # echo LANG=en_US.UTF-8 > /etc/locale.conf
- 设置用户级别的 locale
用 su 切换到刚建立的用户,然后编辑 ~/.bashrc 修改自己的 Locale ,例如:
LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL=
(为啥不是 ~/.config/locale.conf 了啊…… 其实咱也不知道…… )
于是现在大概就有了这个样子:
(这个在终端里显示发行版等信息的软件是 screenfetch 啦,也有人喜欢另一个 小修改版 neofetch )
设置 SSH 和 SD 卡访问
SSH 的话,生成好主机密钥然后再启动 sshd 就可以:
## 在有 systemd 这样的 init 系统的发行版上启动 sshd 时会帮汝运行这一步, ## 不过这里就只有自己代劳啦…… # ssh-keygen -A ## 这里一定要是绝对路径,不然就会出 "sshd re-exec requires execution with an absolute path" 错误。 # /usr/bin/sshd
然后就可以用一个新的终端模拟器窗口通过 ssh 连接进来啦……
clover:/ $ ssh [email protected] The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established. ECDSA key fingerprint is SHA256: . Are you sure you want to continue connecting (yes/no/[fingerprint])? yes [email protected]'s password: [horo@localhost ~]$
要是汝在登录时遇到了 PTY allocation failed on channel 0 这样的错误,在 chroot 里(重新) 挂载一下 /dev/pts 试试?
# umount /dev/pts # mount -t devpts devpts /dev/pts
以及可以的话记得修改 /etc/sshd_config 把 sshd 限定到只允许本地连接?
要把 SD 卡挂载到哪里的话,在 chroot 的外面运行:
## 当然汝的 /sdcard 可能是汝的内存设备什么的,别忘了自己调整路径…… # mkdir /data/linux/arch/mnt/sdcard # mount -o bind /sdcard /data/linux/arch/mnt/sdcard
总结?
所以有 Linux Deploy 那样好用(?)的工具了为啥不直接拿来用呢(划掉)
以及纯粹是闲的,找一台正经的电脑装正经的 GNU/Linux 不好么 (x)
喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。
发布评论…