OpenWrt Forum Archive

Topic: UPDATED 'BootFromExternalMediaHowTo'

The content of this topic has been archived on 27 Mar 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

Hi guys, I have a Routerstation Pro and it only has 16mb of flash, but it has an SD-Card slot, so I want to run my os off the sd-card instead. I tried following the instructions in the guide at http://oldwiki.openwrt.org/OpenWrtDocs% … HowTo.html and it got me most of the way there but I ran into a few problems and ended up having to modify the main script that it uses (/etc/init.d/bootext) quite a bit. I figured I would share the updated version with you guys. I have allowed it to remain completely abstracted and generic so it should run on anyone's setup. Should wink

#!/bin/sh /etc/rc.common

START=11
STOP=91

bootext_cleanup() { # [cleanup_level]
 [ "$1" -ge 3 ] && grep -q '^[^ ]* /rom ' /proc/mounts && mount -o move /rom $putold/rom
 [ "$1" -ge 2 ] && { . $putold/bin/firstboot ; 
            umount /config ;
            mount -o move /proc $putold/proc ;
            pivot_root $putold $putold$target ; 
            mount -o move $target/dev /dev ;
            mount -o move $target/tmp /tmp ;
            mount -o move $target/sys /sys ; }
 [ "$1" -ge 1 ] && umount -l $target/etc
 return 0
}

bootext_fail() { # <error_message> [cleanup_level]
 echo "$1" >&2
 [ ! "$2" ] || bootext_cleanup $2
 exit 1
}

bootext_quit() { # <message>
 echo "$1" >&2
 exit 0
}

bootext_start() {
 ! grep -q "^$device / " /proc/mounts || bootext_quit "$name already on /"

 if ! grep -q "^$device $target " /proc/mounts
 then
  ! grep -q "^$device " /proc/mounts || bootext_fail "$name already mounted"

  for module in $modules
  do
   if ! grep -q "^$module " /proc/modules
   then
    [ $module != mmc ] || [ ! "$gpiomask" ] || echo "$gpiomask" > /proc/diag/gpiomask || bootext_fail "could not set gpiomask"
    insmod $module || bootext_fail "could not insert $module module"
   fi
  done

  while [ ! -b $device ]
  do
   [ "$waitdev" -gt 0 ] || bootext_fail "$device does not exist"
   waitdev=$(( $waitdev - 1 ))
   sleep 1
  done

  [ -d $target ] || mkdir $target || bootext_fail "could not create mountpoint $target"
  mount ${filesys:+-t $filesys} ${mountopt:+-o $mountopt} $device $target || bootext_fail "could not mount $name on $target"
 fi

 [ -d $target$putold ] || mkdir $target$putold || bootext_fail "could not create mountpoint $putold"
 [ -d $target/etc ] || mkdir $target/etc || bootext_fail "could not create mountpoint /etc"
 mount -o bind /etc $target/etc || bootext_fail "could not bind mount /etc"

 [ -d $target/proc ] || mkdir $target/proc || bootext_fail "could not create mountpoint /proc "
 mount -o move /proc $target/proc || bootext_fail "could not bind mount /proc"

 . /bin/firstboot
 pivot_root $target $target$putold || bootext_fail "could not pivot to $target" 1

 [ -d /dev ] || mkdir /dev || bootext_fail "could not create mountpoint /dev "
 mount -o move $putold/dev /dev

 [ -d /tmp ] || mkdir /tmp || bootext_fail "could not create mountpoint /tmp "
 mount -o move $putold/tmp /tmp

 [ -d /sys ] || mkdir /sys || bootext_fail "could not create mountpoint /sys "
 mount -o move $putold/sys /sys

 [ -d /config ] || mkdir /config || bootext_fail "could not create mountpoint /config "
 mount -o bind $putold/config /config

 ! grep -q "^[^ ]* $putold/rom " /proc/mounts || { [ -d /rom ] || mkdir /rom && mount -o move $putold/rom /rom ; }

 return 0
}

bootext_stop() {
 grep -q "^$device / " /proc/mounts || bootext_quit "$name not on /"

 bootext_cleanup 999
}

bootext_config() { # <section> <action>
 local section=$1
 local action=$2
 local enabled device name target putold modules gpiomask waitdev filesys mountopt

 config_get_bool enabled $section enabled 1
 [ "$enabled" -gt 0 ] || return 0
 config_get device $section device
 [ "$device" ] || bootext_fail "external boot device not configured"
 config_get name $section name
 config_get target $section target
 config_get putold $section putold
 config_get modules $section modules
 config_get gpiomask $section gpiomask
 config_get waitdev $section waitdev
 config_get filesys $section filesys
 config_get mountopt $section mountopt

 [ "$name" ] || name="$device"
 [ "$putold" ] || putold="${target:-/old}"
 [ "$target" ] || target="/${filesys:-new}"

 bootext_$action
}

start() {
 config_load bootfromexternalmedia
 config_foreach bootext_config bootfromexternalmedia start
}

stop() {
 config_load bootfromexternalmedia
 config_foreach bootext_config bootfromexternalmedia stop
}

Essentially the changes are:
-Pivot has been renamed pivot_root in the distro at some point so the script needed to be updated to call the new name for the binary
-Handles /proc
-Handles /dev
-Handles /tmp
-Handles /sys
-Handles /config
-I went along with the theme of the original developer and included error checking along the way.
-It should also be able to put everything back in the original location if you run '/etc/init.d/bootext stop'


I have tested this out a bit on my own system, but maybe some other people should give it a shot too. So far it works great on my RSPRO.
Make sure to read that wiki article linked above as there is some other stuff you need to do on your box to make this work (you need to make a config file in the /etc/config folder mainly)


Also, it would be nice to add something that moves all of your mounted stuff from /mnt/whatever in the old root to /mnt/whatever in the new root. I know there is a way to do this programmaticly but I am actually a beginner to shell scripting. I am actually a windows guy really, so this stuff is a bit new to me at this point. Any help would be appreciated, or I'll just figure it out on my own eventually.


Here is a quick sanity check:

(After a clean boot)

root@OpenWrt:/# df -h        (Original Mounts)

Filesystem                Size      Used Available Use% Mounted on
/dev/root                14.9M     14.8M    112.0K  99% /
devtmpfs                512.0K      4.0K    508.0K   1% /dev
tmpfs                    62.0M     84.0K     61.9M   0% /tmp
tmpfs                   512.0K      4.0K    508.0K   1% /dev
/dev/sda1               116.7M     33.8M     76.8M  31% /mnt/sda1
/dev/sda2               116.9M      5.5M    105.4M   5% /mnt/sda2

root@OpenWrt:/# /etc/init.d/bootext start

root@OpenWrt:/# df -h        (Modified Mounts)

Filesystem                Size      Used Available Use% Mounted on
/dev/root                14.9M     14.6M    252.0K  98% /mnt/oldroot
devtmpfs                 61.9M         0     61.9M   0% /mnt/oldroot/dev
tmpfs                    62.0M     84.0K     61.9M   0% /tmp
tmpfs                   512.0K         0    512.0K   0% /dev
/dev/sda1               116.7M     33.8M     76.8M  31% /
/dev/sda2               116.9M      5.5M    105.4M   5% /mnt/oldroot/mnt/sda2
/dev/root                14.9M     14.6M    252.0K  98% /etc

root@OpenWrt:/# /etc/init.d/bootext stop

root@OpenWrt:/# df -h        (Original Mounts, matches first one above)

Filesystem                Size      Used Available Use% Mounted on
/dev/root                14.9M     14.6M    252.0K  98% /
devtmpfs                512.0K         0    512.0K   0% /dev
tmpfs                    62.0M     84.0K     61.9M   0% /tmp
tmpfs                   512.0K         0    512.0K   0% /dev
/dev/sda1               116.7M     33.8M     76.8M  31% /mnt/sda1
/dev/sda2               116.9M      5.5M    105.4M   5% /mnt/sda2

Enjoy! Happy coding and happy Valentines Day!

(Last edited by extide on 14 Feb 2010, 19:55)

RS-Pro, Backfire 10.3b:

- /dev/diag/gpio... doesn't exist (workaround: don't set any gpio in the config file)
- mount -t fstype doesn't work (workaround: don't set any fs in the config file)
- /bin/firstboot is /sbin/firstboot
- firstboot (just before pivot_root) doesn't find /proc/mtd and /proc/mounts
...

I stopped debugging when I found

http://wiki.openwrt.org/doc/howto/rootf … nalstorage

There's an option in buildroot that makes this stuff obsolete: on backfire there's a package to do it automagically.
Great job everybody.

Dogge wrote:

You should use the new block-extroot package for external rootfs.

See: http://wiki.openwrt.org/doc/howto/rootf … nalstorage

According to opkg info, block-extroot must be compiled right into the image flashed to the router.  That seems like a very serious limitation when there are alternatives I can use from a stock install.

Mactalla:

block-extroot is tiny. It's not the file system or any of the tools. It's just a "stub" used by the sysinit to pivot over to the filesystem (i.e., a filesystem formatted on USB, for example) you specify. The additional benefit is that it is really, really simple to configure and activate. Assuming your USB stick (or onboard USB flash) is formatted already and you copy over your JFFS partition to it, all you need to do is make or change a few variables in the /etc/config/fstab then reboot to activate.

It's a lot less painful than every other method I have seen. Takes me about 5 minutes to get everything going on a new board.

Try it.

marc.

I have no problem with the size.  I know it's tiny.  The point I brought up is that it claims to need to be built right into the image, meaning someone who wants to go this route must setup a whole dev environment for OpenWrt and build a custom image for their router.  This completely negates the whole point of having pre-built images for the various routers available for download.  I agree it would be nice to have a prepared package to not need to manually install the pivotroot scripts (the method I'm currently using).  But that small bit of manual work is less than creating my own images.

mactalla wrote:

The point I brought up is that it claims to need to be built right into the image, meaning someone who wants to go this route must setup a whole dev environment for OpenWrt and build a custom image for their router.

Building from source is the recommended way to go with OpenWrt. It's easy to use the build-system and with a VM a development environment is setup quickly.

(Last edited by Dogge on 18 Mar 2010, 10:28)

I just switched over to the jffs2 image and the block-extroot package works well without needing to build a custom image.  Thanks guys.

It's not recommended to use the jffs2 image...

Mactalla:

There is no reason to use the JFFS2 image instead of squashfs, especially as it's quite a bit larger than squashfs.

marc.

marca56 wrote:

There is no reason to use the JFFS2 image instead of squashfs, especially as it's quite a bit larger than squashfs.

I wanted to try out block-extroot, and according to opkg:

$ opkg info block-extroot
Package: block-extroot
[...]
Description: Based on the moduluarized preinit and firstboot, adds the option to have
 the root filesystem on storage other than the jffs or the boot root device.
 For a squashfs image this package must be installed into the image, not as
 a package to add later.
Installed-Time: 167

Says I couldn't do it with squashfs.

Not that the size of JFFS2 is a concern since most packages are installed on the USB drive.

I strongly recommend trying method described by wzab in this topic:
https://forum.openwrt.org/viewtopic.php?id=23901
It is described as destined for WL500-gPv2, but should work other routers too.

It gives you flexibility to run not only filesystem, but also kernel from USB!
For me it means no more flashing my router *ever*. Even if there comes new kernel, I only have to update files on USB disk.

The discussion might have continued from here.