嗨嗨,我愛 Termux {% fa_inline terminal %}!
Termux Environment Setup
因為最近買了一隻想拿來亂玩亂刷 ROM 的手機,每次刷都有可能會清掉裡面所存好的資料, 那就會需要重新建立帳號或是環境。其他的程式可能沒有太大的問題, 雖然也沒有使用鈦備份之類的,但大多是登入帳號頂多稍微選個佈景主題之類的就好了, 但還是有些需要有比較多設定,就有點麻煩。 {% blockquote %} 而 Termux 的環境設定會是需要花比較多步驟才能達到順手的地步。 {% endblockquote %}
所以就寫了一個環境設定自動化的 Script,以減少設定成本, 可以好好來刷機而不用擔心設定好麻煩。
About Termux
Termux 是一個在 Android 下的終端機模擬器,但它又附上了一個可以用擴充的套件系統,
就像使用一般 Ubuntu/Debian Linux 一樣,透過 apt 這個命令,
就可以經由網路安裝或是更新程式了。比起之前用的方法,大致上都是在裡面掛上一個真正的
Linux 影像檔,然後再 chroot 過去,Termux 這種明顯跟原本的
Android 系統就比較好的整合性,比如可以在 Termux 裡面寫 Script 分享網址,
或是查詢聯絡人之類的,都可以做得到。
{% blockquote %}
關於 Termux 一定會寫好幾篇的。
{% endblockquote %}
Termux Environment Setup Script
因為設定 Script 相當個人化,雖然已經儘量減少洩漏但還是有些風險, 所以就沒有放出來公開分享。不過還是會把裡面有用到值得一提的部份寫一下。
Initial script
首先是一開始裝完 Termux 之後,是一個很乾淨的系統狀態下, 要怎麼很快速簡潔又安全地執行一個 Script 呢?就是放到一個自己的網頁位址上, 然後用 goo.gl 縮個網址,就可以得到一組很簡單的短網址, 像是這樣 **http://goo.gl/123abc**。
而乾淨的 Termux 系統中,已經有一個 Busybox 的 wget 了,
所以只要這樣就可以:
$ rm 123abc; wget goo.gl/123abc && bash 123abc
[Y]/n in apt install
接下來要安裝以及更新一些必要的套件,但通常下 apt install 的命令的時候,
都會再問一下說有確定要裝嗎 [Y]/n?每次都要按個 Enter,也是有點麻煩。
關於這個部份,apt 有提供一個參數 -y,就可以預設是 yes 了。
$ apt upgrade -y
$ apt install -y proot
(yes) and password: in ssh
一樣地,ssh 與 scp 命令,也會遇到第一次連線的時候,會需要輸入
(yes),已建立新的連線。而在還沒有把 private key 抓回來之前,
也會需要輸入一次密碼,遇到了就會停下來等待輸入才有辦法繼續,不太自動。
所以會在一開始的時候,就先把密碼問一下,然後再利用 sshpass
這個工具來解決第一次需要密碼的問題。而第一次的連線的時候,可以下
StrictHostKeyChecking=no 參數,避免要等待輸入 (yes)。
echo "Please input password for the first time"
read -s P
[ -f $HOME/.ssh/id_rsa ] && SSHPASS="" || SSHPASS="sshpass -p $P"
$SSHPASS ssh -o StrictHostKeyChecking=no sshserver ls
Here document to config file
因為 Termux 環境跟 Ubuntu/Debian Linux 環境還是有點不一樣,
有些程式所參考的位置,在 Termux 就不一定會出現。像是 /etc/shells
這個檔案會紀錄著 Linux 系統中所有可能的 shells,而 oh-my-zsh
安裝的時候會檢查這個檔案中有沒有 zsh,不然就不裝了。
只好自己產生一個:
# shells
cat > /etc/shells <<EOF
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/tmux
/bin/zsh
/use/bin/zsh
EOF
Multiple stages before/after chroot
好的,問題來了。
如果進去到 Termux 的視窗中,就會發現它的確還是在 Android 底下,
不信可以先 ls / 看看,完全就是個 Android 根目錄的樣子。
shebang
這代表一件事,如果沒有特別處理,開頭長得像這樣的 Script 是沒有辦法直接執行的。
#!/bin/sh
這東西有個專有名詞叫作 Shebang。
Termux 有提供一個指令 termux-fix-shebang,它會自動把上面的
Shebang 改成 Termux 的路徑:
#!/data/data/com.termux/files/user/bin/bash
chroot
{% blockquote %}
但是每個 Script 都需要 fix 的話,相當不好用啊。
{% endblockquote %}
所以 Termux 也有另外一個指令 termux-chroot,是基於 proot
包裝成的 chroot 環境,其實就是把根目錄換成剛剛的 /data/data/com.termux/files。
$ termux-chroot
$ ls /
bin dev home proc storage tmp var
data etc lib share system usr
chroot in script
在安裝個人環境的 Setup Script,會需要進入到 termux-chroot 環境中的
不然會遇到路徑找不到的錯誤,像是用 repo init -u 的時候,就會有問題。
但是直接寫在 termux-chroot 後面命令,是不會被執行到的,更正確地說,
是離開了 chroot 環境才會繼續執行下去。
$ cat setup.sh
...
termux-chroot
ls /
這很常見,因為 termux-chroot 會產生一個互動的 login shell。
通常 chroot 會可以接受參數,指定新環境下要跑的命令。
$ chroot --help
Usage: chroot [OPTION] NEWROOT [COMMAND [ARG]...]
不過 termux-chroot 就不允許這樣了,看了一下原始碼,是不接受參數的。
if [ $# != 0 ]; then
echo "termux-chroot: Setup a chroot to mimic a normal Linux file system"
echo ""
echo "Execute without arguments to run a chroot with traditional file system"
echo "hierarchy (having e.g. the folders /bin, /etc and /usr) within Termux."
exit
fi
...
ARGS="$ARGS $PROGRAM -l"
export HOME=/home
$PREFIX/bin/proot $ARGS
雖然 termux-chroot 不行,但原始碼看得出來 proot 是可以指定
ARGS 變數,換成自己的,就可以寫在 Script 自動執行 chroot
後的命令了。
mutiple stages
所以最後的 Setup Script 架構大概長成這樣子,分成兩階段執行, 這樣就可以放下去跑,然後休息一下,等它們全部設定完就好了。
zero() {
# before termux-chroot
apt install proot
...
prepare-termux-chroot
export HOME=/home
$PREFIX/bin/proot $ARGS /bin/bash $0 1
}
first() {
# after termux-chroot
ls /
}
if [ $# -eq 0 ]; then
zero
fi
if [ $# -eq 1 ]; then
first
fi
termux-exec (2018)
Sat, 28 Jul 2018 23:22:14 +0800
其實這個 setup script ,現在已經不是上面寫的這種程序了,現在的版本簡單很多, 大致上改了底下幾個部份:
termux-exec
首先就是使用 termux-exec 取代了 proot,proot 在某些 Android O 的手機上會有權限的問題,原本需要使用 proot 的地方現在可以使用 termux-exec 來替換了喔,問題就是發生在許多的 Linux scripts 寫的時候都會想要先去找** /bin/sh 或是 /usr/bin/env **, 這個上面 Shebang 也有提到。偏偏 Android 並不是這樣放的 termux-exec 利用 LD_PRELOAD 換掉 execve() ,然後接到 Termux 環境相對應的執行檔,是個相當漂亮又乾淨的作法。
StrictHostKeyChecking
ssh 在第一次連接到 Host 的時候都會問像下面的訊息,
The authenticity of host hostname '(192.188.1.1)' can\'t be established.
ECDSA key fingerprint is SHA256:+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no)?
其實可以直接將 StrictHostKeyChecking no 寫進 .ssh/config 初始設定裡, 避免 setup script 卡住等待回應,
[ -d $HOME/.ssh ] || mkdir -p $HOME/.ssh
cat > $HOME/.ssh/config << EOF
Host git
Hostname git.domain.name
User git
StrictHostKeyChecking no
EOF
here document for private key
本來是另外要抓 ssh 的 private key 回來放的,但其實也是可以利用 Here Documents,直接嵌入在這個 setup script 裡,如此一來只要抓取一個檔案就夠, 當然這個檔案其實也就不好放在大家都看得到的地方了。
# use here document with id_rsa-termux
cat > $HOME/.ssh/id_rsa << EOF_ID_RSA
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
EOF_ID_RSA
mod 600 $HOME/.ssh/id_rsa
repo and zsh
因為 Termux 上的 /usr/bin/env python 是 python3,所以抓下來的 repo 要提換成 python2,
mkdir -p $HOME/bin
curl https://storage.googleapis.com/git-repo-downloads/repo | sed 's/env python$/env python2/g' > $HOME/bin/repo
chmod a+x $HOME/bin/repo
而在設定 oh-my-zsh 的時候,本來是需要檢查 /etc/shells,現在則改用替換 oh-my-zsh 的安裝 script 方式,避掉這個檢查,
zsh: SHELL:=bash
zsh:
[ -d ~/.oh-my-zsh ] || { \
if [ "$$OSTYPE" = linux-android ]; then \
curl -L http://install.ohmyz.sh | sed 's/chsh -s.*$$/chsh -s zsh/g' | bash; \
else \
curl -L http://install.ohmyz.sh | bash; \
fi \
}
repo (2019)
Thu, 28 Nov 2019 23:35:34 +0800
某次更新的時候,發覺 repo 自己抓新的 scripts,就出現找不到 env python
類似的訊息,就不能正常使用了。又不想要弄個 proot,所以趁這次機會就把 repo
換成 git 的 submodules,這樣只要 git 一隻程式就可以了。
後來也為了自己的 submodules 寫了一些幫忙的工具,也是相當方便。