Newer
Older
# _____ _ _
# | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# | __| _| -_| -_| . | . | | . | . | | -_|
# |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___|
# To shut down after error: fuser -mvk /tmp/tmpdir/build
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Bob Mottram
committed
PROJECT_NAME='freedombone'
PROJECT_INSTALL_DIR=/usr/local/bin
if [ -f /usr/bin/${PROJECT_NAME} ]; then
PROJECT_INSTALL_DIR=/usr/bin
fi
PROJECT_REPO="https://code.freedombone.net/bashrc/${PROJECT_NAME}"
UTILS_FILES="/usr/share/${PROJECT_NAME}/utils/${PROJECT_NAME}-utils-*"
# fixed username and password when the --generic option is used
GENERIC_IMAGE_USERNAME='fbone'
GENERIC_IMAGE_PASSWORD='freedombone'
IMAGE_TYPE='beagleboneblack'
UNIQUE_ID=$(openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c 10 ; echo -n '')
VMDEBOOTSTRAP_REPO=git://git.liw.fi/vmdebootstrap
VMDEBOOTSTRAP_VERSION=0.8
MAKEFILE=${PROJECT_NAME}-image-makefile
# filename where the build progress will be logged to
BUILD_LOG=
# IP address of the router (gateway)
ROUTER_IP_ADDRESS="192.168.1.254"
# The fixed IP address of the Beaglebone Black (or other SBC) on your local network
BOX_IP_ADDRESS="192.168.1.55"
# DNS
NAMESERVER1='91.239.100.100'
NAMESERVER2='89.233.43.71'
NAMESERVER3='213.73.91.35'
NAMESERVER4='85.214.73.63'
NAMESERVER5='84.200.69.80'
NAMESERVER6='84.200.70.40'
Bob Mottram
committed
# An optional freedombone configuration file
CONFIG_FILENAME=
DEFAULT_DOMAIN_NAME="${LOCAL_NAME}.local"
MINIMUM_PASSWORD_LENGTH=$(grep 'MINIMUM_PASSWORD_LENGTH=' "/usr/share/${PROJECT_NAME}/utils/${PROJECT_NAME}-utils-passwords" | head -n 1 | awk -F '=' '{print $2}')
# Optional ssh public key to allow
SSH_PUBKEY="no"
# interactive mode
INTERACTIVE="no"
# Whether this is a generic image for mass redistribution on the interwebs
# Whether to reduce the number of decisions during interactive install
MINIMAL_INSTALL="yes"
# default SSH port
SSH_PORT=2222
# Whether sites are accessible only within a Tor browser
ONION_ONLY="no"
# Where to fetch packages
#MIRROR='http://httpredir.debian.org/debian'
MIRROR='http://ftp.de.debian.org/debian'
# Whether to only install debian but nothing else
DEBIAN_INSTALL_ONLY='no'
# wifi settings
WIFI_INTERFACE='wlan0'
WIFI_SSID=
WIFI_PASSPHRASE=
WIFI_HOTSPOT='no'
# Whether to install non-free wifi drivers for the mesh client
INSECURE='no'
# for mesh installs whether to delete all data and generate
# a new identity at every shutdown/boot
AMNESIC='no'
# Versions used for Arch/Parabola setup
MBR_VERSION='1.1.11'
# version of cliapp to use with parabola
CLIAPP_COMMIT='cb17626e6441a5bf43a1d3f17a769f8e44ff4977'
# version of mbr to use with parabola
MBR_COMMIT='fb7ac88f251a1529b8aa759abc49acb2e99094b2'
# defining repo variables here ensures that they will be mirrored
MULTIPATH_TOOLS_REPO="https://aur.archlinux.org/multipath-tools.git"
MBR_REPO="https://aur.archlinux.org/mbr.git"
CLIAPP_REPO="git://git.liw.fi/cliapp"
# Whether to use a SATA drive and if so what its device/partition name is
# eg. sda2
EXTERNAL_DRIVE=
function image_setup {
setup_type=$1
case $setup_type in
debian|ubuntu|trisquel|mint)
# NOTE: These packages aren't available on ARM
sudo $INSTALL_PACKAGES gcc-multilib g++-multilib
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES libc6-dev-i386
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES extlinux
# shellcheck disable=SC2086
sudo $REMOVE_PACKAGES vmdebootstrap
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES build-essential libc6-dev
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES git python-docutils mktorrent xz-utils
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES_BACKPORTS debootstrap
sudo $INSTALL_PACKAGES dosfstools btrfs-tools python-distro-info mbr
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES qemu-user-static binfmt-support u-boot-tools qemu
# shellcheck disable=SC2086
sudo $INSTALL_PACKAGES python-cliapp kpartx
sudo cp /sbin/install-mbr /usr/bin/install-mbr
;;
parabola|arch)
sudo pacman -S --noconfirm libc++ git gcc gcc-libs python-docutils mktorrent patch
sudo pacman -S --noconfirm debootstrap xz dosfstools btrfs-progs syslinux python-pip
sudo pacman -S --noconfirm qemu-static binfmt-qemu-static uboot-tools qemu parted
sudo pacman -S --noconfirm dpkg-devtools bin86 arch-install-scripts qemu-arch-extra
sudo pacman -S --noconfirm syncthing bin86 patch pkg-config debian-archive-keyring
mkdir "$USERHOME/develop"
if [ -d "$USERHOME/develop/python-cliapp" ]; then
sudo rm -rf "$USERHOME/develop/python-cliapp"
if ! git_clone "$CLIAPP_REPO" "$USERHOME/develop/python-cliapp"; then
echo $"Failed to clone python-cliapp"
return
fi
echo $"Couldn't clone python-cliapp"
return
fi
sudo pacman -S --noconfirm python2-coverage python2-pytest-cov python2-sphinx
sudo pacman -S --noconfirm autopep8 python2-pylint python2-yaml python2-xdg python2-pip
cd "$USERHOME/develop/python-cliapp" || exit 78
git checkout $CLIAPP_COMMIT -b $CLIAPP_COMMIT
sudo python2 setup.py install
sudo pip2 install distro-info logging
if [ -d "$USERHOME/develop/mbr" ]; then
sudo rm -rf "$USERHOME/develop/mbr"
echo $"Failed to clone mbr"
return
fi
echo $"Couldn't clone mbr"
return
fi
cd "$USERHOME/develop/mbr" || exit 24
git checkout $MBR_COMMIT -b $MBR_COMMIT
makepkg --force --noconfirm
if [ ! -f mbr-${MBR_VERSION}.tar.gz ]; then
echo $"mbr tarball was not found for version ${MBR_VERSION}"
return
fi
tar -xzvf mbr-${MBR_VERSION}.tar.gz
echo $"mbr tarball could not be extracted"
return
fi
cd "$USERHOME/develop/mbr/mbr-${MBR_VERSION}" || exit 13
cp ../*.patch .
patch -p0 < *.patch
./configure
make
sudo make install
if [ ! -f /usr/local/sbin/install-mbr ]; then
echo $'Failed to install mbr'
return
fi
sudo cp /usr/local/sbin/install-mbr /sbin
if [ -d "$USERHOME/develop/multipath-tools" ]; then
sudo rm -rf "$USERHOME/develop/multipath-tools"
if ! git_clone "$MULTIPATH_TOOLS_REPO" "$USERHOME/develop/multipath-tools"; then
echo $"Failed to clone multipath-tools"
return
fi
echo $"Couldn't clone multipath-tools"
return
sudo pacman -S --noconfirm device-mapper libaio liburcu fakeroot
cd "$USERHOME/develop/multipath-tools" || exit 27
makepkg --force --noconfirm
makepkg -i --force --noconfirm
sudo wget "https://code.freedombone.net/bashrc/${PROJECT_NAME}/raw/master/image_build/debootstrap/scripts/${DEBIAN_VERSION}" -O /usr/share/debootstrap/scripts/debscript
sudo wget "https://code.freedombone.net/bashrc/${PROJECT_NAME}/raw/master/image_build/debootstrap/scripts/debian-common" -O /usr/share/debootstrap/scripts/debian-common
sudo cp -f "/usr/share/debootstrap/scripts/debscript" "/usr/share/debootstrap/scripts/${DEBIAN_VERSION}"
if [ ! -f "/usr/share/debootstrap/scripts/${DEBIAN_VERSION}" ]; then
echo $"No debian debootstrap script was found for $DEBIAN_VERSION"
debian_script_hash=$(sha256sum "/usr/share/debootstrap/scripts/${DEBIAN_VERSION}" | awk -F ' ' '{print $1}')
expected_debian_script_hash='f3f13f568fef7955682e1a15a075bce4d664ca84e94b153acecee50e202b3ae9'
if [[ "$debian_script_hash" != "$expected_debian_script_hash" ]]; then
echo $"Invalid hash for debootstrap ${DEBIAN_VERSION} script"
return
fi
;;
*)
echo $'Unkown operating system'
return
;;
esac
echo $'Setup complete'
}
function mesh_router_setup_script {
# create a setup script for a mesh router
mesh_script_filename=$1
{ echo "MY_USERNAME=${USERNAME}";
echo "DEFAULT_DOMAIN_NAME=${USERNAME}";
echo 'SYSTEM_TYPE=mesh';
echo 'INSTALLING_ON_BBB=no';
echo 'USB_DRIVE=/dev/sda1';
echo 'DDNS_PROVIDER=';
echo 'DDNS_USERNAME=';
echo 'DDNS_PASSWORD=';
echo 'DEFAULT_LANGUAGE=en_GB.UTF-8';
echo 'MY_EMAIL_ADDRESS=';
echo 'ENABLE_BATMAN=yes';
echo 'DEBIAN_REPO=';
echo 'NAMESERVER1=';
echo 'NAMESERVER2=';
echo 'NAMESERVER3=';
echo 'NAMESERVER4=';
echo 'NAMESERVER5=';
echo 'NAMESERVER6=';
echo 'BATMAN_CELLID=any';
echo 'WIFI_CHANNEL=9'; } > "$mesh_script_filename"
if [[ $- != *i* ]]; then
echo $'The image command should be run within an interactive shell'
key="$1"
case $key in
-h|--help)
show_help
;;
-c|--config)
shift
CONFIG_FILENAME="$1"
echo $"Config file $CONFIG_FILENAME not found"
exit 3
fi
DEFAULT_DOMAIN_NAME=$(grep 'DEFAULT_DOMAIN_NAME' "$CONFIG_FILENAME" | awk -F '=' '{print $2}')
;;
-t|--target|--board)
shift
IMAGE_TYPE="$1"
;;
--build-log)
shift
BUILD_LOG="$1"
;;
-u|--user|--username)
shift
USERNAME="$1"
;;
-p|--password)
shift
PASSWORD="$1"
echo $"Your password chould contain at least ${MINIMUM_PASSWORD_LENGTH} characters"
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
fi
;;
--sshkey|--sshpubkey|--pubkey)
shift
SSH_PUBKEY="$1"
;;
-s|--size)
shift
IMAGE_SIZE="$1"
IMAGE_SIZE_SPECIFIED=1
;;
# Box static IP address on the LAN
--ip)
shift
BOX_IP_ADDRESS="$1"
;;
# Router IP address on the LAN
--iprouter)
shift
ROUTER_IP_ADDRESS="$1"
;;
# nameserver 1
--ns1|--nameserver1)
shift
NAMESERVER1="$1"
;;
# nameserver 2
--ns2|--nameserver2)
shift
NAMESERVER2="$1"
;;
# nameserver 3
--ns3|--nameserver3)
shift
NAMESERVER2="$1"
;;
# nameserver 4
--ns4|--nameserver4)
shift
NAMESERVER4="$1"
;;
# nameserver 5
--ns5|--nameserver5)
shift
NAMESERVER5="$1"
;;
# nameserver 6
--ns6|--nameserver6)
shift
NAMESERVER6="$1"
;;
-i|--interactive)
shift
INTERACTIVE="$1"
;;
--ci)
shift
CONTINUOUS_INTEGRATION="$1"
;;
-g|--generic)
shift
GENERIC_IMAGE="$1"
;;
--minimal)
shift
MINIMAL_INSTALL="$1"
;;
--ssh|--sshport)
shift
SSH_PORT="$1"
;;
-v|--variant)
shift
VARIANT="$1"
;;
-o|--onion|--onion-addresses|--onion-addresses-only)
shift
ONION_ONLY="$1"
;;
-a|--amnesic)
shift
AMNESIC="$1"
;;
-r|--repo|--repository)
shift
PROJECT_REPO="$1"
;;
-m|--mirror)
shift
MIRROR="$1"
;;
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
shift
DEBIAN_INSTALL_ONLY="$1"
;;
--interface|--if)
shift
WIFI_INTERFACE="$1"
;;
--ssid|--essid)
shift
WIFI_SSID="$1"
;;
--wifitype)
shift
WIFI_TYPE="$1"
;;
--wifipass|--passphrase)
shift
WIFI_PASSPHRASE="$1"
;;
--hotspot)
shift
if [[ $"$1" == $'yes' || $"$1" == $'y' ]]; then
WIFI_HOTSPOT='yes'
fi
;;
--networks)
shift
WIFI_NETWORKS_FILE="$1"
;;
--insecure)
shift
INSECURE="$1"
;;
--setup)
shift
image_setup "$1"
exit 0
;;
--local|--localname)
shift
LOCAL_NAME="$1"
;;
--sata|--hdd)
shift
EXTERNAL_DRIVE="$1"
;;
*)
# unknown option
;;
esac
shift
if [[ "$INTERACTIVE" == "yes" || "$INTERACTIVE" == "y" || "$INTERACTIVE" == "Yes" ]]; then
${PROJECT_NAME}-config --minimal "$MINIMAL_INSTALL"
DEFAULT_DOMAIN_NAME=$(grep 'DEFAULT_DOMAIN_NAME' "$CONFIG_FILENAME" | awk -F '=' '{print $2}')
USERNAME=$GENERIC_IMAGE_USERNAME
PASSWORD=$GENERIC_IMAGE_PASSWORD
# generate a random password
PASSWORD=$(openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c "${MINIMUM_PASSWORD_LENGTH}")
# shellcheck disable=SC2068
for im in ${image_types[@]}
no_of_files=$(ls -afq ${CURR_DIR}/${PROJECT_NAME}*.${im} | wc -l)
if (( no_of_files > 0 )); then
if [ ! -d "${CURR_DIR}/build" ]; then
mkdir "${CURR_DIR}/build"
# shellcheck disable=SC2086
mv -f ${CURR_DIR}/${PROJECT_NAME}*.${im} ${CURR_DIR}/build
# shellcheck disable=SC2068
for im in ${image_types[@]}
no_of_files=$(ls -afq ${CURR_DIR}/${PROJECT_NAME}*.${im} | wc -l)
if (( no_of_files > 0 )); then
if [ -f "${CURR_DIR}/${PROJECT_NAME}_login_credentials.txt" ]; then
rm "${CURR_DIR}/${PROJECT_NAME}_login_credentials.txt"
IMAGE_NAME=$'onion'
if [[ $ONION_ONLY == "no" ]]; then
IMAGE_NAME=$'sata'
else
IMAGE_NAME=$'onion-sata'
fi
if [[ "$IMAGE_TYPE" == 'beagle'* ]]; then
# Size which can fit within emmc
if [ ! $IMAGE_SIZE_SPECIFIED ]; then
IMAGE_SIZE=3.8G
fi
fi
IMAGE_NAME=$'mesh'
# typically not much disk space is needed for a mesh node
if [ ! $IMAGE_SIZE_SPECIFIED ]; then
if [[ "$VARIANT" == 'meshclient' || $VARIANT == 'meshusb' ]]; then
IMAGE_NAME=$'meshclient'
if [[ $INSECURE != 'no' ]]; then
IMAGE_NAME=$'meshclient-insecure'
fi
#if [ ! $IMAGE_SIZE_SPECIFIED ]; then
# IMAGE_SIZE=9.0G
#fi
IMAGE_NAME=$'usb'
IMAGE_NAME="${IMAGE_NAME}-amnesic"
if [ "${IMAGE_NAME}" ]; then
TEMPBUILD_DIR=~/.tmp_${PROJECT_NAME}_build_${IMAGE_TYPE}-${IMAGE_NAME}
else
TEMPBUILD_DIR=~/.tmp_${PROJECT_NAME}_build_${IMAGE_TYPE}
fi
if [ -d "$TEMPBUILD_DIR" ]; then
rm -rf "$TEMPBUILD_DIR"
mkdir -p "$TEMPBUILD_DIR"
cp "/usr/local/bin/$MAKEFILE" "$TEMPBUILD_DIR/Makefile"
cp "/usr/bin/$MAKEFILE" "$TEMPBUILD_DIR/Makefile"
cp -r /etc/${PROJECT_NAME}/* "$TEMPBUILD_DIR"
rm -rf "$TEMPBUILD_DIR/vendor"
chown -R "$CURR_USER":"$CURR_USER" "$TEMPBUILD_DIR"
cd "$TEMPBUILD_DIR" || exit 24
cd "$TEMPBUILD_DIR" || exit 72
MYUSERNAME="$USERNAME" \
MYPASSWORD="$PASSWORD" \
ROUTER_IP_ADDRESS="$ROUTER_IP_ADDRESS" \
BOX_IP_ADDRESS="$BOX_IP_ADDRESS" \
NAMESERVER1="$NAMESERVER1" \
NAMESERVER2="$NAMESERVER2" \
NAMESERVER3="$NAMESERVER3" \
NAMESERVER4="$NAMESERVER4" \
NAMESERVER5="$NAMESERVER5" \
NAMESERVER6="$NAMESERVER6" \
PROJECT_NAME="$PROJECT_NAME" \
CONFIG_FILENAME="$CONFIG_FILENAME" \
IMAGE_SIZE="$IMAGE_SIZE" \
SSH_PUBKEY="$SSH_PUBKEY" \
GENERIC_IMAGE="$GENERIC_IMAGE" \
MINIMAL_INSTALL="$MINIMAL_INSTALL" \
SSH_PORT="$SSH_PORT" \
ONION_ONLY="$ONION_ONLY" \
IMAGE_NAME="$IMAGE_NAME" \
PROJECT_REPO="$PROJECT_REPO" \
MIRROR="$MIRROR" \
BUILD_MIRROR="$MIRROR" \
DEBIAN_INSTALL_ONLY="$DEBIAN_INSTALL_ONLY" \
WIFI_INTERFACE="$WIFI_INTERFACE" \
WIFI_SSID="$WIFI_SSID" \
WIFI_TYPE="$WIFI_TYPE" \
WIFI_PASSPHRASE="$WIFI_PASSPHRASE" \
WIFI_HOTSPOT="$WIFI_HOTSPOT" \
WIFI_NETWORKS_FILE="$WIFI_NETWORKS_FILE" \
VARIANT="$VARIANT" \
MINIMUM_PASSWORD_LENGTH="$MINIMUM_PASSWORD_LENGTH" \
INSECURE="$INSECURE" \
CONTINUOUS_INTEGRATION="$CONTINUOUS_INTEGRATION" \
echo $'Build failed'
exit 1
EXPECTED_EXTENSION='qcow2'
echo $'Image was not created'
exit 2
# Move images from temporary directory to the current directory
# shellcheck disable=SC2068
for im in ${image_types[@]}
no_of_files=$(ls -l build/${PROJECT_NAME}*.${im} | wc -l)
if [ "$no_of_files" -gt 0 ]; then
# shellcheck disable=SC2086
mv build/${PROJECT_NAME}*.${im} ${CURR_DIR}/
# move the build log so it's accessible to CI
if [ -f "build/${PROJECT_NAME}*.log" ]; then
mv "build/${PROJECT_NAME}*.log" "${CURR_DIR}"/build.txt
fi
mv "${TEMPBUILD_DIR}"/* "${CURR_DIR}"
rm -rf "${TEMPBUILD_DIR}"
cd "${CURR_DIR}" || exit 28
echo $"
If necessary, ssh access can be enabled from the settings screen of the web interface.
# record the default login credentials for later use
Password: $PASSWORD" > "${CURR_DIR}/${PROJECT_NAME}_login_credentials.txt"
chmod 600 "${CURR_DIR}/${PROJECT_NAME}_login_credentials.txt"
IMAGE_FILENAME=$(find . -name "*.img" | grep -v 'build/' | head -n 1 | awk -F '/' '{print $2}')
else
IMAGE_FILENAME=$(find . -name "*.qcow2" | grep -v 'build/' | head -n 1 | awk -F '/' '{print $2}')
fi
echo ''
echo $'To compress:'
echo ''
echo " sudo chown $CURR_USER: ${IMAGE_FILENAME}"
echo " xz --no-warn --verbose --keep --threads=0 -3 ${IMAGE_FILENAME}"
echo ''
echo $'To sign:'
echo ''
echo " gpg -ba ${IMAGE_FILENAME}.xz"
echo ''
if [[ "$IMAGE_TYPE" != "qemu"* ]]; then
echo 'To copy to microSD, USB drive or SSD'
echo ''
echo ' sudo dd if=/dev/zero of=/dev/sdX bs=1M count=8'
echo " sudo dd bs=1M if=${IMAGE_FILENAME} of=/dev/sdX conv=fdatasync,sync,noerror"
echo ''