├── .gitignore ├── README.md ├── RESEARCH.md ├── mkeosdrive └── mkeosimg /.gitignore: -------------------------------------------------------------------------------- 1 | *.img 2 | *.tar 3 | *.gz 4 | *~ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mkeosimg 2 | 3 | Your EdgeRouter's internal USB drive died, and you don't have a spare 4 | couple hours to figure out how TFTP works. Run this script instead *on 5 | your nearest Linux machine* and generate a .img that you can dd straight 6 | to a new USB drive. 7 | 8 | If you want to create a USB boot drive directly, use `./mkeosdrive` instead. 9 | 10 | # Usage 11 | 12 | * `sudo ./mkeosimg ER-e100.v1.xxxxxxx.tar` (you downloaded that file 13 | from the [Ubiquiti](https://www.ui.com/download/edgemax) site. Pick 14 | the latest system update for your router). 15 | 16 | * If you have a backup config file that you'd like to include, such as 17 | edgeos_routername_NNNNNNNN.tar.gz, just provide the path to it as the 18 | second parameter. 19 | 20 | * If you want to use more of the available space on a larger flash drive, 21 | you can enter the total image size in GB as the third parameter. 22 | If you don't want to provide a config file, but still want to have a 23 | larger image, use "-" (without the quotes) as the second parameter. 24 | If no drive size is specified, the script will default to 2 GB. 25 | 26 | * Download the resulting .img if you built this elsewhere (such as on 27 | a Google Compute Engine instance that you spun up just for this 28 | project). You should have gzipped it because that'll make it around 29 | 20x smaller. 30 | 31 | * `sudo dd if=ER-e100.v1.xxxxxxx.img of=/dev/path/to/usb/drive bs=1M` 32 | (adapt to your OS of choice) to write the image to your USB drive. 33 | 34 | * If you want, you can directly create a USB drive without creating an 35 | image file first. Use `./mkeosdrive` instead, and supply the target 36 | device as the first parameter. All other parameters are shifted by one 37 | position accordingly. 38 | 39 | `sudo ./mkeosdrive /dev/path/to/usb/drive ER-e100.v1.xxxxxxx.tar` 40 | 41 | * Insert the new USB drive into your router and boot it up. If you 42 | included your backup config in the first step, then your router will 43 | start shuttling around packets on your network just like it used to; 44 | otherwise you'll have to set it up as a brand-new device. 45 | 46 | # Troubleshooting 47 | 48 | * Did everything, but router's still not booting? Your USB drive might 49 | be on the slow side. See [issue 50 | #7](https://github.com/sowbug/mkeosimg/issues/7) for more detail, 51 | and thanks [@kosta](https://github.com/kosta) for filing the issue. 52 | 53 | # Credits and Miscellaneous 54 | 55 | Inspired by 56 | https://github.com/vyos/emrk/blob/master/bin/emrk-reinstall. Some parts 57 | of the code were stolen from there as well. 58 | 59 | Beware! There are lots of things out there that call themselves "EMRK" 60 | and succeed to varying degrees in helping with EdgeRouter unbricking. 61 | -------------------------------------------------------------------------------- /RESEARCH.md: -------------------------------------------------------------------------------- 1 | $ ls -ln /media/miket/0000-0020/ 2 | total 7893 3 | -rw-r--r-- 1 1000 1000 8081560 Jun 4 2013 vmlinux.64 4 | -rw-r--r-- 1 1000 1000 33 Jun 26 2013 vmlinux.64.md5 5 | 6 | $ ls -ln /media/miket/0dfee33a-fc90-431f-a278-d29092e294c7/ 7 | total 62232 8 | drwx------ 2 0 0 16384 Dec 31 1969 lost+found 9 | -rw-r--r-- 1 0 0 63623168 Jun 26 2013 squashfs.img 10 | -rw-r--r-- 1 0 0 33 Jun 26 2013 squashfs.img.md5 11 | -rw-r--r-- 1 0 0 41 Jun 26 2013 version 12 | drwxr-xr-x 7 0 0 4096 Jun 1 2011 w 13 | drwxr-xr-x 2 33 0 4096 Jun 1 2011 www 14 | 15 | $ cat /media/miket/0dfee33a-fc90-431f-a278-d29092e294c7/version 16 | Version: v1.2.0.4574253.130626.1248 17 | 18 | /mnt/squash$ ls -ln 19 | total 0 20 | drwxr-xr-x 2 0 0 1028 Jun 26 2013 bin 21 | drwxr-xr-x 2 0 0 3 Feb 18 2013 boot 22 | drwxrwsr-x 7 0 102 95 Jun 26 2013 config 23 | drwxr-xr-x 5 0 0 880 Jun 26 2013 dev 24 | drwxr-xr-x 75 0 0 2525 Jun 26 2013 etc 25 | drwxr-xr-x 2 0 0 3 Feb 18 2013 home 26 | drwxr-xr-x 9 0 0 2788 Jun 26 2013 lib 27 | drwxr-xr-x 2 0 0 3 Jun 26 2013 media 28 | drwxr-xr-x 2 0 0 3 Feb 18 2013 mnt 29 | drwxr-xr-x 3 0 0 29 Jun 20 2013 opt 30 | drwxr-xr-x 2 0 0 3 Feb 18 2013 proc 31 | drwxr-xr-x 2 0 0 46 Jun 26 2013 root 32 | drwxr-xr-x 2 0 0 3 Jun 26 2013 root.dev 33 | drwxr-xr-x 2 0 0 1572 Jun 26 2013 sbin 34 | drwxr-xr-x 2 0 0 3 Jul 21 2010 selinux 35 | drwxr-xr-x 2 0 0 3 Jun 26 2013 srv 36 | drwxr-xr-x 2 0 0 3 Mar 27 2012 sys 37 | drwxrwxrwt 2 0 0 3 Jun 26 2013 tmp 38 | drwxr-xr-x 10 0 0 150 Jun 26 2013 usr 39 | drwxr-xr-x 16 0 0 209 Jun 26 2013 var 40 | -------------------------------------------------------------------------------- /mkeosdrive: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit script on any error 4 | set -e 5 | 6 | if [ "$EUID" -ne 0 ] 7 | then 8 | echo "Must run as root or with sudo." 9 | exit 1 10 | fi 11 | 12 | DEVICE=${1} 13 | TARBALL=${2} 14 | CONFIG=${3} 15 | DRIVESIZE=${4} 16 | 17 | DEVICE_BOOT=${DEVICE}1 18 | DEVICE_ROOT=${DEVICE}2 19 | 20 | BOOT_MNT=/mnt/boot 21 | ROOT_MNT=/mnt/root 22 | 23 | if [[ -z "$TARBALL" ]] 24 | then 25 | echo "Usage: ./mkeosdrive /dev/yourUSBdrive system_image.tar \ 26 | " 27 | echo "If you want to provide a root partition end cap size but no config, use \"-\" without the quotes as the third parameter." 28 | exit 1 29 | fi 30 | 31 | mkdir -p $BOOT_MNT 32 | mkdir -p $ROOT_MNT 33 | 34 | # Unmount all partitions on device 35 | umount "${DEVICE}"? && echo "Unmounted all partitions on $DEVICE" || echo "no filesystem mounted from $DEVICE" 36 | 37 | # Unmount folders only if already mounted 38 | grep -qs "$BOOT_MNT" /proc/mounts && umount $BOOT_MNT 39 | grep -qs "$ROOT_MNT" /proc/mounts && umount $ROOT_MNT 40 | 41 | DIR=$(mktemp -d) 42 | 43 | function cleanup { 44 | if [ -d "$DIR" ] 45 | then 46 | rm -rf "$DIR" 47 | fi 48 | if [ -d "$BOOT_MNT" ] 49 | then 50 | rm -rf "$BOOT_MNT" 51 | fi 52 | if [ -d "$ROOT_MNT" ] 53 | then 54 | rm -rf "$ROOT_MNT" 55 | fi 56 | } 57 | trap cleanup EXIT 58 | 59 | echo "Press any key to continue formatting $DEVICE" 60 | read -n1 -rsp $'or hit Ctrl+C to exit now...\n' 61 | 62 | # deleting existing partiton table first 63 | dd if=/dev/zero of="$DEVICE" bs=512 count=1 conv=notrunc 64 | 65 | echo "Waiting for disk sync..." 66 | sync 67 | 68 | parted --script "$DEVICE" mktable msdos 69 | parted --script "$DEVICE" mkpart primary fat32 1 150MB 70 | 71 | # If no drive size was supplied as a parameter, default to full size root partition 72 | if [ -n "$DRIVESIZE" ] 73 | then 74 | echo "Creating root partition with an end cap size of $DRIVESIZE GB" 75 | (( SIZE = $DRIVESIZE * 1024 )) 76 | parted --script "$DEVICE" mkpart primary ext3 150MB "${SIZE}"MB 77 | else 78 | parted --script "$DEVICE" mkpart primary ext3 150MB 100% 79 | fi 80 | 81 | echo "Waiting for disk sync..." 82 | sync 83 | 84 | # Add a delay to allow the system to recognize the new partitions 85 | sleep 2 86 | 87 | echo "Formatting $DEVICE partitions..." 88 | mkfs.msdos -F 32 "$DEVICE_BOOT" 89 | mkfs.ext3 -q "$DEVICE_ROOT" 90 | 91 | echo "Waiting for disk sync..." 92 | sync 93 | 94 | mount "$DEVICE_BOOT" $BOOT_MNT 95 | mount "$DEVICE_ROOT" $ROOT_MNT 96 | 97 | echo "Unpacking EdgeOS release image" 98 | tar xf "$TARBALL" -C "$DIR" 99 | 100 | ####### Kernel 101 | echo "Verifying EdgeOS kernel" 102 | if [ "$(md5sum "$DIR"/vmlinux.tmp | awk -F ' ' '{print $1}')" != \ 103 | "$(cat "$DIR"/vmlinux.tmp.md5)" ]; then 104 | echo "Kernel in image is corrupted! Check your image and start over." 105 | exit 1 106 | fi 107 | 108 | echo "Copying EdgeOS kernel to boot partition" 109 | cp "$DIR"/vmlinux.tmp $BOOT_MNT/vmlinux.64 110 | cp "$DIR"/vmlinux.tmp.md5 $BOOT_MNT/vmlinux.64.md5 111 | 112 | ####### System 113 | echo "Verifying EdgeOS system image" 114 | if [ "$(md5sum "$DIR"/squashfs.tmp | awk -F ' ' '{print $1}')" != \ 115 | "$(cat "$DIR"/squashfs.tmp.md5)" ]; then 116 | echo "System in image is corrupted! Check your image and start over." 117 | exit 1 118 | fi 119 | 120 | echo "Copying EdgeOS system image to root partition" 121 | mv "$DIR"/squashfs.tmp $ROOT_MNT/squashfs.img 122 | mv "$DIR"/squashfs.tmp.md5 $ROOT_MNT/squashfs.img.md5 123 | 124 | echo "Copying version file to the root partition" 125 | mv "$DIR"/version.tmp $ROOT_MNT/version 126 | 127 | # Writable data dir 128 | echo "Creating EdgeOS writable data directories" 129 | mkdir $ROOT_MNT/w 130 | mkdir $ROOT_MNT/www 131 | 132 | chown 33:0 $ROOT_MNT/www 133 | 134 | ####### Extract config 135 | if [ -n "$CONFIG" ] && [ -f "$CONFIG" ] 136 | then 137 | echo "Config archive $CONFIG was provided, extracting it to the root partition..." 138 | tar xf "$CONFIG" -C $ROOT_MNT/w 139 | else 140 | echo "No config archive was provided, default settings will be used." 141 | fi 142 | 143 | echo "Waiting for disk sync..." 144 | sync 145 | 146 | echo "Unmounting filesystems on $DEVICE..." 147 | umount $ROOT_MNT 148 | umount $BOOT_MNT 149 | 150 | echo "Done. You can now plug the USB drive back into your router and boot it." 151 | -------------------------------------------------------------------------------- /mkeosimg: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$EUID" -ne 0 ] 4 | then 5 | echo "Must run as root or with sudo." 6 | exit 1 7 | fi 8 | 9 | TARBALL=${1} 10 | CONFIG=${2} 11 | DRIVESIZE=${3} 12 | DEVICE=$(losetup -f) 13 | DEVICE_BOOT=${DEVICE}p1 14 | DEVICE_ROOT=${DEVICE}p2 15 | 16 | BOOT_MNT=/mnt/boot 17 | ROOT_MNT=/mnt/root 18 | 19 | if [[ -z "$TARBALL" ]] 20 | then 21 | echo "Usage: ./mkeosimg system_image.tar \ 22 | " 23 | echo "If you want to provide an image size but no config, use \"-\" without the quotes as the second paramenter." 24 | exit 1 25 | fi 26 | 27 | mkdir -p $BOOT_MNT 28 | mkdir -p $ROOT_MNT 29 | 30 | # unmount only if already mounted 31 | grep -qs "$BOOT_MNT" /proc/mounts && umount $BOOT_MNT 32 | grep -qs "$ROOT_MNT" /proc/mounts && umount $ROOT_MNT 33 | 34 | DIR=$(mktemp -d) 35 | 36 | function cleanup { 37 | if [ -d "$DIR" ] 38 | then 39 | rm -rf "$DIR" 40 | fi 41 | if [ -d "$BOOT_MNT" ] 42 | then 43 | rm -rf "$BOOT_MNT" 44 | fi 45 | if [ -d "$ROOT_MNT" ] 46 | then 47 | rm -rf "$ROOT_MNT" 48 | fi 49 | } 50 | trap cleanup EXIT 51 | 52 | ####### Check if config was supplied as a parameter and if it exists as a file 53 | if [ -n "$CONFIG" ] && [ -f "$CONFIG" ] 54 | then 55 | CONFIGURED_SUFFIX="-configured" 56 | else 57 | CONFIGURED_SUFFIX="" 58 | fi 59 | 60 | IMG=${TARBALL%.tar}${CONFIGURED_SUFFIX}.img 61 | rm -f "$IMG.gz" 62 | 63 | # If no drive size was supplied as a parameter, default to 2 GB 64 | if [ -z "$DRIVESIZE" ] 65 | then 66 | DRIVESIZE=2 67 | fi 68 | 69 | echo "Creating $IMG with a size of $DRIVESIZE GB" 70 | (( SIZE = DRIVESIZE * 1024 )) 71 | dd if=/dev/zero of="$IMG" bs=1M count=0 seek="$SIZE" 72 | losetup "$DEVICE" "$IMG" 73 | parted --script "$DEVICE" mktable msdos 74 | parted --script "$DEVICE" mkpart primary fat32 1 150MB 75 | parted --script "$DEVICE" mkpart primary ext3 150MB 100% 76 | 77 | echo "Formatting $IMG" 78 | mkfs.msdos -F 32 "$DEVICE_BOOT" 79 | mkfs.ext3 -q "$DEVICE_ROOT" 80 | 81 | mount "$DEVICE_BOOT" $BOOT_MNT 82 | mount "$DEVICE_ROOT" $ROOT_MNT 83 | 84 | echo "Unpacking EdgeOS release image" 85 | tar xf "$TARBALL" -C "$DIR" 86 | 87 | ####### Kernel 88 | echo "Verifying EdgeOS kernel" 89 | if [ "$(md5sum "$DIR"/vmlinux.tmp | awk -F ' ' '{print $1}')" != \ 90 | "$(cat "$DIR"/vmlinux.tmp.md5)" ]; then 91 | echo "Kernel in image is corrupted! Check your image and start over." 92 | exit 1 93 | fi 94 | 95 | echo "Copying EdgeOS kernel to boot partition" 96 | cp "$DIR"/vmlinux.tmp $BOOT_MNT/vmlinux.64 97 | cp "$DIR"/vmlinux.tmp.md5 $BOOT_MNT/vmlinux.64.md5 98 | 99 | ####### System 100 | echo "Verifying EdgeOS system image" 101 | if [ "$(md5sum "$DIR"/squashfs.tmp | awk -F ' ' '{print $1}')" != \ 102 | "$(cat "$DIR"/squashfs.tmp.md5)" ]; then 103 | echo "System in image is corrupted! Check your image and start over." 104 | exit 1 105 | fi 106 | 107 | echo "Copying EdgeOS system image to root partition" 108 | mv "$DIR"/squashfs.tmp $ROOT_MNT/squashfs.img 109 | mv "$DIR"/squashfs.tmp.md5 $ROOT_MNT/squashfs.img.md5 110 | 111 | echo "Copying version file to the root partition" 112 | mv "$DIR"/version.tmp $ROOT_MNT/version 113 | 114 | # Writable data dir 115 | echo "Creating EdgeOS writable data directories" 116 | mkdir $ROOT_MNT/w 117 | mkdir $ROOT_MNT/www 118 | 119 | chown 33:0 $ROOT_MNT/www 120 | 121 | ####### Extract config 122 | if [ -n "$CONFIG" ] && [ -f "$CONFIG" ] 123 | then 124 | tar xf "$CONFIG" -C $ROOT_MNT/w 125 | fi 126 | 127 | # These need to happen before the losetup -d, or else the changes won't be 128 | # written to disk 129 | umount $ROOT_MNT 130 | umount $BOOT_MNT 131 | 132 | # Unhook img 133 | losetup -d "$DEVICE" 134 | 135 | echo "Done." 136 | --------------------------------------------------------------------------------