From a4e2fe02b68f866e8d242b7d4669744cd2dff6d5 Mon Sep 17 00:00:00 2001
From: Jeroen Massar <jeroen@massar.ch>
Date: Wed, 2 Oct 2019 11:33:07 +0200
Subject: [PATCH 1/3] Enable detection of bmaptool, and if present generate
 sparse files.

This uses https://github.com/intel/bmap-tools to generate a .bmap file
which can be copied around. The bmaptool allows storing sparse files
onto for instance an SD card, thus avoiding having to transfer the full
disk image every time one burns one.
Thus saving lots of time (and SD card cycles).

This also adds some instructions for then transfering and copying the
sparse file.

bmaptool: info: discovered bmap file '/Users/jeroen/berry.img.bmap'
bmaptool: info: block map format version 2.0
bmaptool: info: 7324219 blocks of size 4096 (27.9 GiB), mapped 1539940 blocks (5.9 GiB or 21.0%)
bmaptool: info: copying image 'berry.img' to file 'rdisk4' using bmap file 'berry.img.bmap'
bmaptool: info: 100% copied
bmaptool: info: synchronizing '/dev/rdisk4'
bmaptool: info: copying time: 6m 49.7s, copying speed 14.7 MiB/sec

versus copying the whole 30G which would take forever...
---
 .gitignore                |  1 +
 scripts/create_sibling.sh | 63 +++++++++++++++++++++++++++++++++++----
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/.gitignore b/.gitignore
index 1ed1207..7d065ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 *.img
+*.img.bmap
 *.pcap
 __pycache__
 _backups
diff --git a/scripts/create_sibling.sh b/scripts/create_sibling.sh
index c69ff84..e8e1396 100755
--- a/scripts/create_sibling.sh
+++ b/scripts/create_sibling.sh
@@ -5,14 +5,17 @@
 set -eu
 
 REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 )
+DEBREQUIREMENTS=( wget gzip git parted qemu-system-x86 qemu-user-static parted bmap-tools )
 REPO_DIR="$(dirname "$(dirname "$(realpath "$0")")")"
 TMP_DIR="${REPO_DIR}/tmp"
 MNT_DIR="${TMP_DIR}/mnt"
+THIS_DIR=$(pwd)
 
 PWNI_NAME="pwnagotchi"
 PWNI_OUTPUT="pwnagotchi.img"
 PWNI_SIZE="4"
 
+OPT_SPARSE=0
 OPT_PROVISION_ONLY=0
 OPT_CHECK_DEPS_ONLY=0
 OPT_IMAGE_PROVIDED=0
@@ -26,6 +29,18 @@ if [[ "$EUID" -ne 0 ]]; then
 fi
 
 function check_dependencies() {
+  if [ -f /etc/debian_version ];
+  then
+    echo "[+] Checking Debian dependencies"
+
+    for REQ in "${DEBREQUIREMENTS[@]}"; do
+      if ! dpkg -s "$REQ" >/dev/null 2>&1; then
+        echo "Dependency check failed for ${REQ}; use 'apt-get install ${REQ}' to install"
+        exit 1
+      fi
+    done
+  fi
+
   echo "[+] Checking dependencies"
   for REQ in "${REQUIREMENTS[@]}"; do
     if ! type "$REQ" >/dev/null 2>&1; then
@@ -76,8 +91,31 @@ function provide_raspbian() {
 }
 
 function setup_raspbian(){
-  echo "[+] Resize image"
-  dd if=/dev/zero bs=1G count="$PWNI_SIZE" >> "${TMP_DIR}/raspbian.img"
+  # Detect the ability to create sparse files
+  if [ "${OPT_SPARSE}" -eq 0 ];
+  then
+    which bmaptool >/dev/null 2>&1
+    if [ $? -eq 0 ];
+    then
+      echo "[+] Defaulting to sparse image generation as bmaptool is available"
+      OPT_SPARSE=1
+    else
+      echo "[!] bmaptool not available, not creating a sparse image"
+    fi
+  fi
+
+  # Note that we 'extend' the raspbian.img
+  if [ "${OPT_SPARSE}" -eq 1 ];
+  then
+    # Resize sparse (so that we can use bmaptool later)
+    echo "[+] Resizing sparse image of ${PWNI_SIZE}GB (1000s)"
+    truncate -s ${PWNI_SIZE}GB "${TMP_DIR}/raspbian.img"
+  else
+    echo "[+] Resizing full image to ${PWNI_SIZE}G"
+    # Full disk-space using image (appends to raspbian image)
+    dd if=/dev/zero bs=1G count="${PWNI_SIZE}" >> "${TMP_DIR}/raspbian.img"
+  fi
+
   echo "[+] Setup loop device"
   mkdir -p "${MNT_DIR}"
   LOOP_PATH="$(losetup --find --partscan --show "${TMP_DIR}/raspbian.img")"
@@ -107,7 +145,7 @@ function provision_raspbian() {
   cd "${MNT_DIR}"
   sed -i'' 's/^\([^#]\)/#\1/g' etc/ld.so.preload # add comments
   echo "[+] Run chroot commands"
-  LANG=C chroot . bin/bash -x <<EOF
+  LANG=C LC_ALL=C LC_CTYPE=C chroot . bin/bash -x <<EOF
   set -eu
   export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 
@@ -203,7 +241,11 @@ EOF
   cd "${REPO_DIR}"
   umount -R "${MNT_DIR}"
   losetup -D "$(losetup -l | awk '/raspbian\.img/{print $1}')"
-  mv "${TMP_DIR}/raspbian.img" "$PWNI_OUTPUT"
+  mv "${TMP_DIR}/raspbian.img" "${PWNI_OUTPUT}"
+  if [ "${OPT_SPARSE}" -eq 1 ];
+  then
+    bmaptool create -o "${PWNI_OUTPUT}.bmap" "${PWNI_OUTPUT}"
+  fi
 }
 
 function usage() {
@@ -216,6 +258,7 @@ usage: $0 [OPTIONS]
     -i <file>    # Provide the path of an already downloaded raspbian image
     -o <file>    # Name of the img-file (default: pwnagotchi.img)
     -s <size>    # Size which should be added to second partition (in Gigabyte) (default: 4)
+    -S           # Create a sparse image and generate bmap file (default when bmaptool is available)
     -v <version> # Version of raspbian (Supported: ${SUPPORTED_RASPBIAN_VERSIONS[*]}; default: latest)
     -p           # Only run provisioning (assumes the image is already mounted)
     -d           # Only run dependencies checks
@@ -283,4 +326,14 @@ fi
 setup_raspbian
 provision_raspbian
 
-echo -ne "[+] Congratz, it's a boy (⌐■_■)!\n[+] One more step: dd if=../$PWNI_OUTPUT of=<PATH_TO_SDCARD> bs=4M status=progress"
+echo -e "[+] Congratz, it's a boy (⌐■_■)!"
+echo -e "[+] One more step: dd if=../${PWNI_OUTPUT} of=<PATH_TO_SDCARD> bs=4M status=progress"
+
+if [ "${OPT_SPARSE}" -eq 1 ];
+then
+  echo -e "[t] To transfer use: rsync -vaS --progress $(whoami)@$(hostname -f):${THIS_DIR}/../${PWNI_OUTPUT} <DEST>"
+  echo -e "[t] To burn with bmaptool: bmaptool copy ~/${PWNI_OUTPUT} /dev/<DEVICE>"
+fi
+
+# Helpful OSX reminder
+echo -e "[t] Mac: use 'diskutil list' to figure out which device to burn to; 'diskutil unmountDisk' to unmount that disk'; then use /dev/rdiskX (note the 'r') for faster transfer"

From 4c20314c907279a852e04cc37dd00efcf7525609 Mon Sep 17 00:00:00 2001
From: Jeroen Massar <jeroen@massar.ch>
Date: Wed, 2 Oct 2019 11:57:25 +0200
Subject: [PATCH 2/3] Update dependencies, as travis needs bmap-tools now to
 perform CI

---
 .travis.yml               | 2 +-
 scripts/create_sibling.sh | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index b173709..8a41478 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,7 @@ cache:
   - tmp/
 before_script:
 - sudo apt-get -y update
-- sudo apt-get -y install qemu-user-static binfmt-support qemu
+- sudo apt-get -y install qemu-user-static binfmt-support qemu bmap-tools
 - sudo update-binfmts --display
 - unset GOROOT
 script:
diff --git a/scripts/create_sibling.sh b/scripts/create_sibling.sh
index e8e1396..f9b9bd0 100755
--- a/scripts/create_sibling.sh
+++ b/scripts/create_sibling.sh
@@ -5,7 +5,7 @@
 set -eu
 
 REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 )
-DEBREQUIREMENTS=( wget gzip git parted qemu-system-x86 qemu-user-static parted bmap-tools )
+DEBREQUIREMENTS=( wget gzip git parted qemu-system-x86 qemu-user-static bmap-tools )
 REPO_DIR="$(dirname "$(dirname "$(realpath "$0")")")"
 TMP_DIR="${REPO_DIR}/tmp"
 MNT_DIR="${TMP_DIR}/mnt"

From 14f1e4bccb6b2293f87496d9e33475a186771bc0 Mon Sep 17 00:00:00 2001
From: Jeroen Massar <jeroen@massar.ch>
Date: Wed, 2 Oct 2019 12:23:30 +0200
Subject: [PATCH 3/3] Enlarge the created disk to 8G, as it already fails
 during image creation with out of diskspace

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 8a41478..4928b9e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@ before_script:
 - sudo update-binfmts --display
 - unset GOROOT
 script:
-- sudo ./scripts/create_sibling.sh -n pwnagotchi -o pwnagotchi.img -s 4
+- sudo ./scripts/create_sibling.sh -n pwnagotchi -o pwnagotchi.img -s 8
 - zip -s 2g pwnagotchi.zip pwnagotchi.img
 
 # TODO: deploy!