I was preparing to overwrite the onboard flash with my new image, but I was growing apprehensive. I had access to the system mtd-write tool through ssh, but it wasn't working and was compiled without any error messages. I then came up with the idea of building an image similar to those provided by ASUS that I could feed into the regular firmware update utility. I didn't really want to do this so I checked around the community one more time for alternative ideas.
For some background: I used the router for a good long time, but I was outgrowing it a little, and I wanted some additional capabilities like split DNS and VLANs which the stock firmware cannot do. I would have flashed the router with one of the open source firmwares like OpenWRT, AsusWRT-Merlin, or DD-WRT but somehow I accidentally purchased one of the few models not supported by these firmwares because of its proprietary Broadcom kernel and modules. So here we are.
I found a comment on the small net builder forums that there is an nvram variable on most asus routers called script_usbmount. Setting it to a path tells the router to execute the script located at the path when a USB drive is inserted. Now I had a real plan.
I built a crossdev prefix root for the architecture of the router: armv7l-unknown-linux-musleabi. I cross built all the tools I wanted, and then a few more I wanted to try out. I made sure chroot was built as a statically-linked executable. I fleshed out the prefix a little more with the FHS directories like /run, /tmp, /mnt, ... I even installed openrc despite it complaining a little bit. Finally I ran "rsync -a --del . /mnt/gentoo" which copied all of the file onto a USB flash drive formatted with ext3 because that was one of the filesystems the router had builtin.
I ssh'd back into the router and saw that the usb device was mounted automatically and my script_usbmount file executed successfully. After some fiddling around I was able to use the static chroot executable to run the dynamically linked /bin/bash using musl libc. From there I fiddled around some more and tried to get OpenRC working.
OpenRC makes it clear that you are not really supposed to use it on a system that wasn't booted by OpenRC, however if you create the file /run/openrc/softlevel it will stop complaining and go ahead anyways. I had to remove almost every single service file from the runlevels because they would conflict with the router which was already booted. I left swap in the sysinit runlevel and that was it. I wanted to run dnsmasq and metalog but they depended on other virtual services which I had removed.
There was also another problem. The ASUS router already runs its own version of dnsmasq and other daemons which will block the operation of my daemons. I simply created a service called /etc/init.d/usurp which killed these old services and also "provided" the virtual services like net and localmount which I had removed. I added the usurp service to the boot runlevel. Here it is:
Code: Select all
#!/usr/sbin/openrc-run
# Copyright (c) 2007-2015 The OpenRC Authors.
# See the Authors file at the top-level directory of this distribution and
# https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
#
# This file is part of OpenRC. It is subject to the license terms in
# the LICENSE file found in the top-level directory of this
# distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
description="Finalizes setup of chroot and stuff"
depend()
{
provide localmount net netmount
}
start()
{
# Kill processes we are going to replace from the old operating environment
if [ -f "/run/dnsmasq.pid" ] ; then
kill $(cat "/run/dnsmasq.pid")
rm "/run/dnsmasq.pid"
fi
if [ -f "/run/syslogd.pid" ] ; then
kill $(cat "/run/syslogd.pid")
rm "/run/syslogd.pid"
fi
}
stop()
{
return 0;
}
Finally I backed out of the chroot and changed script_usbmount to this:
Code: Select all
#!/bin/sh
PREFIX="/tmp/mnt/gentoo"
# Wait if the mount point isn't actually ready yet
if [ ! -d "${PREFIX}" ] ; then
sleep 5
fi
if [ ! -d "${PREFIX}" ] ; then
echo "Error: prefix not available." >> /jffs/error.txt
fi
# Busybox mount syntax
mount -t proc /proc "${PREFIX}/proc/"
mount -o rbind,rslave /sys "${PREFIX}/sys"
mount -o rbind,rslave /dev "${PREFIX}/dev"
mount -o bind /tmp "${PREFIX}/mnt/tmproot"
mount -o bind /var/run "${PREFIX}/run"
# Tell OpenRC it is not running in a sane environment
mkdir -p "${PREFIX}/run/openrc/"
touch "${PREFIX}/run/openrc/softlevel"
"${PREFIX}/bin/chroot" "${PREFIX}" /usr/sbin/openrc defaultAll that done and I'm surprised but it actually works. Of course it didn't work on the first try but its running now. And anytime I want to go back to stock configuration I can just umount and remove the usb drive.
