前段时间,由于家中无人,水管突然爆裂,导致水漫金山,以致于把我珍藏多年的高配 TP-Link 给活生生的淹死了。想当年克俭克勤,好不容易买来准备把玩 Openwrt 的( 后来忘了这茬 ),看来梦想终是破灭了。
于是,在家人好言相劝并不断督促的前提下,我怒下重金在京东买了 小米路由3 。一个炎热而又百般无聊的下午,京东快递小哥暧昧的给我递上一个包裹,小米路由安静而美丽的躺在里面,久违的清风吹过,家人乐了,而老司机我这次却坐不住了。
这一次,一定要抽空把玩下这货,以免人生再留下遗憾啊!
一转眼几周过去了,老司机觉得时机已经成熟,可以对它动手了。而这首当其冲的,是需要我们去剥开它的外衣,直入主题。开启 SSH 后,才可以让我们对它一览无遗,而要开启小米路由3的 SSH,首先我们要升级它的 ROM,稳定版是不能开启的。
升级很简单,我们进入这个网址:
http://www1.miwifi.com/miwifi_download.html
选择 ROM 标签,然后下载小米路由3的开发版 ROM, 注意不要选错路由器哦 。我目前下载到的版本是 2.13.33
,然后进入小米路由器管理界面: http://192.168.31.1 ,进入 [常用设置] -> [系统状态] ,点击 [手动升级] ,然后选择你下载的 ROM,一段时间的等待后,再进入系统状态查看就已经是你升级的开发版啦。
有了开发版这个前提,老司机可以带你用官方工具来开启 SSH 了,进入官方的这个地址:
http://www1.miwifi.com/miwifi_open.html
滚动到 开启SSH工具 这里:
点击进入,这里会显示你 root 的密码,赶快用个小本子记下来吧:
点击下载工具包,然后按照官方的步骤如下:
不过这里老司机要提醒下,如果你的路由没有固定,那么想一个人完成这整个动作有点困难,对于老司机我,当然就轻车熟路了。
一切完毕后,等这一刻是不是已经很久了,那么赶快进入主题吧:
ssh root@192.168.31.1
输入你刚刚记在小本子上的密码,进入后可以看到震撼的欢迎界面:
顿时 雷总被鬼畜后 那魔性的声音在我脑海中旋转起来,老司机欣然的笑了笑,这工程师文化,牛逼!来不及多想,试验了几个命令,发现 opkg
都没有了,看来小米对 openwrt 做了些阉割。扫了扫几个 bin 目录,发现工具还是挺多的,包括一个简化版的 vi。然后再扫了扫 lib 目录,发现里面集成的库还是很多的,值得注意的是 C 标准库用的是 uClibc
。
这时候,如果你想在 /root 目录下建立文件,肯定会报只读的错误,没关系,我们重新挂载下 /root,按下面命令执行:
# cd /data # mkdir -p diy/root # mount diy/root/ /root
这时候再进入 /root 目录下,就可以进行读写操作了,从现在开始,我们可以做一些更有趣的事情,比如写一个小程序玩玩。
小米路由官方提供了 插件开发文档 ,但这种受限且无趣的扩展,老司机是一点都提不起精神,甚至连试都懒得去试。我们需要一些更加激进的玩法,需要更大的掌控权利,所以开发完全原生的应用是个不错的选择。
开发原生应用,那就不得不搭建一个交叉编译环境了,在这之前首先我们要清楚小米路由的 CPU 是什么架构的:
uname -m
输出了 mips
,呃, mips
还有大端 mipsbe
和小端 mipsel
区分,这个在没有法写程序的情况下,还真不好区分。没关系,我们先去官方找找看,有没有现成的交叉环境。
进入刚刚下载开启 SSH 工具的地址: http://www1.miwifi.com/miwifi_open.html
选择 小米路由器插件开发文档 ,下载下来是一个 sdk_package.zip 文件,解压后看到了 toolchain 目录:
什么鬼?怎么这些 toolchain 都是 arm 架构的,完全不符合情理,老司机都不镇定了。用 file
看了下,这些都是 linux 下的二进制文件,作为有追求的 mac 党,果断删、删、删。
于是,抱着好奇的态度,点了旁边 小米路由Mini插件开发文档 ,下载下来是一个 sdk_package_r1c.zip 文件,解压后看到了 toolchain 目录:
这下 CPU 架构对了,看来是小端 mipsel
无疑了,但是老司机怒了,原来这小米路由3就是小米路由mini的升级版啊!没有追求的人可以直接开 linux 虚拟机用这 toolchain 去玩耍了,但老司机是绝对不会做这事。既然官方没有提供 mac 下的 toolchain,老司机决定自己去编译一个。
要在 mac 上编译 openwrt,需要有些准备工作,首先用 brew
安装一些依赖库,逐条执行:
brew tap homebrew/dupes brew install coreutils findutils gawk gnu-getopt gnu-tar grep wget quilt xz brew ln gnu-getopt --force
依赖库安装完后,我们需要导一下环境变量:
export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
其次,mac 的文件系统默认是大小写不明感的( Case-insensitive ),而 openwrt 必须在大小写敏感的( Case-sensitive )文件系统上编译,这点也不难,我们创建一个即可:
hdiutil create -size 10g -type SPARSE -fs "Case-sensitive HFS+" -volname OpenWrt OpenWrt.sparseimage hdiutil attach OpenWrt.sparseimage
创建完毕并附加成功后,我们切入到这个盘中:
cd /Volumes/OpenWrt
接下来就是下载源码了,进入 openwrt 的官方 git 仓库: http://git.openwrt.org ,我们发现最新的稳定版是 15.05
,那我们就选择这个版本。
git clone git://git.openwrt.org/15.05/openwrt.git
等待克隆完毕,老司机就可以带你编译了!
克隆完毕后,我们需要更新和安装下 openwrt 的包列表,执行下面命令:
scripts/feeds update -a scripts/feeds install -a
等待执行完毕后,开始我们的定制化编译配置了,openwrt 这块做得还是非常人性化的,执行 make menuconfig
之后,我们看见一个命令行下的图形化配置界面:
这个界面有点酷啊,注意图中老司机的红色箭头标注,这里选择了系统架构和要构建 toolchain,按两次 ESC,保存后,我们就可以开始编译了。
make toolchain/install
这个要耗蛮久的时间,老司机转身就出门抽烟去了,大概 20 多分钟后它才编译完成,这时候新鲜出炉的 toolchain 就在 staging_dir 目录下了:
这一刻我们已经等得太久了,mac 下的 toolchain 在老司机的轻车熟路下很快就构建了出来,那么我们试试写一个经典的 Hello World
吧!
#include <iostream>
using namespace std;
int main(void) {
cout << "Hello World" << endl;
return 0;
}
编译前,我们需要指定 STAGING_DIR
到 openwrt 编译好的 staging_dir,依次执行如下:
export STAGING_DIR=/Volumes/OpenWrt/openwrt/staging_dir export CXX=/Volumes/OpenWrt/openwrt/staging_dir/toolchain-mipsel_mips32_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mipsel-openwrt-linux-g++ $CXX helloworld.cpp -o helloworld
正确的生成了 helloworld 文件,我们用 file
命令看一下:
helloworld: ELF 32-bit LSB executable, MIPS, MIPS32 version 1, dynamically linked (uses shared libs), with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x3040000, not stripped
现在放到小米路由上试试吧:
scp helloworld root@192.168.31.1:/root/
结果如下图:
这个 Hello World
可真是久违了,那么再来一个更加现代化的 Hello World
:
#include <iostream>
#include <string>
using namespace std;
int main(void) {
[](const std::string &input) {
cout << input << endl;
}("Hello World!");
return 0;
}
使用如下命令编译:
$CXX -std=c++11 helloworld.cpp -o helloworld2
拷贝、执行,完全没问题!你以为这样的 Hello World 就算结束了么?真正的大招现在才开始呢!
Node JS 可以说在跨平台这一块算是做得非常出色的,而在 openwrt 平台上编译 Node JS 也并非难事,最新的非稳定吧 openwrt 中已经包含了 Node 包了,但遗憾的是,最新的 openwrt 使用的是 musl-libc
实现,这个 C 标准库与 uClibc
二进制不兼容,所以编译的二进制文件小米路由3是无法使用的。
老司机灵机一动,想到一个最简单的编译方式,把最新版 openwrt 的 Node 包拷贝到 15.05
中,用 15.05
来编译,如此一来少了很多麻烦的参数配置。于是乎:
cd /Volumes/OpenWrt # 克隆最新版到 openwrt_dev git clone git://git.openwrt.org/openwrt.git openwrt_dev # 拷贝最新版的 feeds 包 cd /Volumes/OpenWrt/openwrt/package cp -rf ../../openwrt_dev/package/feeds .
这些都执行完毕后,我们再回到 openwrt 根目录 make menuconfig
:
注意上图中的层次,保存好后,我们直接 make -j2
,漫长的等待之后,在下面的目录中产生了编译好的 Node:
/Volumes/OpenWrt/openwrt/build_dir/target-mipsel_mips32_uClibc-0.9.33.2/node-v4.4.5/out/Release
我们拷贝到路由上,再次写一个 Hello World
:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('Hello World!/n');
}).listen(8080, '0.0.0.0');
console.log('server running at http://0.0.0.0:8080/');
路由器上跑起来,完全没问题:
本地访问起来,也完全没问题:
折腾下来,发现 openwrt 的可定制程度还是相当高的,小米路由3嘛,就是一个弱鸡!老司机觉得,接下来可以折腾、折腾小米硬件相关的 API 使用了( libroutermain/libxmrouter )。
当然,永远相信,美好的事情即将发生!